+
+
+ {status === "verified"
+ ? (locale === "zh" ? "✓ 真人验证已完成,现在可以注册。" : "✓ Human verification complete. You can create your account now.")
+ : status === "failed"
+ ? (locale === "zh" ? "真人验证没有加载成功,请检查网络或关闭拦截插件后刷新页面。" : "Human verification did not load. Check your connection or content blocker, then refresh.")
+ : status === "ready"
+ ? (locale === "zh" ? "请完成上方真人验证,完成后注册按钮会自动亮起。" : "Complete the check above; the create-account button will enable automatically.")
+ : (locale === "zh" ? "正在加载真人验证…" : "Loading human verification…")}
+
+
;
+}
diff --git a/app/VaultPanel.tsx b/app/VaultPanel.tsx
new file mode 100644
index 0000000..05ed5b3
--- /dev/null
+++ b/app/VaultPanel.tsx
@@ -0,0 +1,361 @@
+"use client";
+
+import { useEffect, useState } from "react";
+import type {
+ CloudState,
+ Debt,
+ Locale,
+ Position,
+ Profile,
+ VaultPayload,
+} from "@/lib/debt-world-types";
+
+type Props = {
+ open: boolean;
+ locale: Locale;
+ cloudState: CloudState;
+ debts: Debt[];
+ profile: Profile;
+ position: Position;
+ discoveryConsent: boolean;
+ onClose: () => void;
+ onStateChange: (state: CloudState) => void;
+ onDiscoveryConsentChange: (consent: boolean) => void;
+ onRestore: (vault: VaultPayload) => void;
+ onDeleted: () => void;
+};
+
+const copy = {
+ zh: {
+ title: "匿名云端保险箱",
+ localTitle: "让角色在不同设备上继续前进",
+ localBody: "登录账号后仍可先在本机整理;主动创建保险箱后,昵称、国家、可选画像、收支、计划和债务才会同步。无需邮箱或手机号。",
+ create: "创建并上传当前记录",
+ recoverTitle: "已有恢复码?",
+ recoverPlaceholder: "DW-XXXX-XXXX-XXXX-XXXX-XXXX-XXXX",
+ recover: "恢复我的角色",
+ synced: "这台设备已连接匿名云端保险箱",
+ syncedBody: "服务器只保存恢复码的不可逆摘要。恢复码本身就是钥匙,请不要截图公开或发送给任何人。",
+ freshTitle: "现在保存恢复码",
+ freshBody: "它只在此刻完整显示。建议保存在自己的密码管理器里;任何拿到它的人都能读取你的记录。",
+ copy: "复制恢复码",
+ copied: "已复制",
+ rotate: "生成新的恢复码",
+ rotateWarning: "生成后,旧恢复码立即失效。",
+ export: "导出我的全部数据",
+ exportLocal: "导出这台设备的数据",
+ deleteTitle: "彻底删除保险箱",
+ deleteBody: "输入 DELETE 后,云端角色、债务和还款记录会永久删除。",
+ delete: "永久删除",
+ close: "关闭",
+ working: "正在处理…",
+ retry: "重新检查连接",
+ discoveryTitle: "参与世界成长(可随时关闭)",
+ discoveryBody: "允许自定义负债名称、大区和可选 MBTI 进入匿名群体统计与新社区候选。准确金额、月收入、私人压力、计划和昵称不会直接公开;画像统计必须达到至少 30 人、每组至少 5 人。",
+ discoveryOff: "默认关闭,不影响云端保存和还款记录。",
+ error: "没有完成,请检查网络后重试。",
+ inviteTitle: "首批真实用户邀请码",
+ inviteBody: "邀请码只控制谁能创建新的匿名保险箱,不会关联真实姓名。每个名额都有总量上限,避免地址外传后产生失控成本。",
+ invitePlaceholder: "例如 SHORE-XXXX-XXXX",
+ betaConsent: "我知道这是早期私测:数据来自本人填写,AI 只提供教育性整理;遇到法律、财务、医疗或紧急安全问题,我会另行联系当地合格专业人士或官方服务。",
+ signupsPaused: "公开测试已暂停新增,但已有恢复码仍可正常恢复。",
+ },
+ en: {
+ title: "Anonymous cloud vault",
+ localTitle: "Continue your person on another device",
+ localBody: "After account sign-in, you may still organize locally. Alias, country, optional profile, cashflow, plans, and debts sync only after you create a vault. No email or phone number is required.",
+ create: "Create vault and upload current records",
+ recoverTitle: "Already have a recovery code?",
+ recoverPlaceholder: "DW-XXXX-XXXX-XXXX-XXXX-XXXX-XXXX",
+ recover: "Recover my person",
+ synced: "This device is connected to an anonymous cloud vault",
+ syncedBody: "The server stores only a one-way hash of the recovery code. The code itself is your key. Never post or send it to anyone.",
+ freshTitle: "Save this recovery code now",
+ freshBody: "It is shown in full only now. Store it in your password manager. Anyone with it can read your records.",
+ copy: "Copy recovery code",
+ copied: "Copied",
+ rotate: "Generate a new recovery code",
+ rotateWarning: "The old code stops working immediately.",
+ export: "Export all my data",
+ exportLocal: "Export this device's data",
+ deleteTitle: "Permanently delete vault",
+ deleteBody: "Type DELETE to permanently remove the cloud person, debts, and payment history.",
+ delete: "Delete permanently",
+ close: "Close",
+ working: "Working…",
+ retry: "Check connection again",
+ discoveryTitle: "Help the world grow (optional)",
+ discoveryBody: "Allow custom debt labels, broad region, and optional MBTI to enter anonymous group statistics and community candidates. Exact amounts, income, private pressure, plans, and aliases are never directly published; profile aggregates require at least 30 people and 5 per group.",
+ discoveryOff: "Off by default. Cloud backup and payment tracking work either way.",
+ error: "That did not finish. Check your connection and try again.",
+ inviteTitle: "First-wave invitation code",
+ inviteBody: "The code controls who can create a new anonymous vault and is not linked to a legal identity. The round has a hard place limit to contain cost if the URL is forwarded.",
+ invitePlaceholder: "For example SHORE-XXXX-XXXX",
+ betaConsent: "I understand this is an early beta: records are self-reported and AI provides educational organization only. I will use qualified local or official help for legal, financial, medical, or immediate-safety needs.",
+ signupsPaused: "Public-beta registration is paused, but existing recovery codes still work.",
+ },
+};
+
+async function readJson(response: Response) {
+ const data = await response.json().catch(() => ({})) as {
+ error?: string;
+ recoveryCode?: string;
+ vault?: VaultPayload;
+ };
+ if (!response.ok) throw new Error(data.error || "Request failed");
+ return data;
+}
+
+export default function VaultPanel({
+ open,
+ locale,
+ cloudState,
+ debts,
+ profile,
+ position,
+ discoveryConsent,
+ onClose,
+ onStateChange,
+ onDiscoveryConsentChange,
+ onRestore,
+ onDeleted,
+}: Props) {
+ const t = copy[locale];
+ const [recoveryInput, setRecoveryInput] = useState("");
+ const [freshCode, setFreshCode] = useState("");
+ const [deleteInput, setDeleteInput] = useState("");
+ const [message, setMessage] = useState("");
+ const [copied, setCopied] = useState(false);
+ const [inviteCode, setInviteCode] = useState("");
+ const [betaConsent, setBetaConsent] = useState(false);
+ const [betaState, setBetaState] = useState<{ signupsEnabled: boolean; inviteRequired: boolean; ready: boolean } | null>(null);
+ const busy = cloudState === "syncing" || cloudState === "checking";
+
+ useEffect(() => {
+ if (!open) return;
+ let cancelled = false;
+ void fetch("/api/beta", { credentials: "same-origin", cache: "no-store" })
+ .then((response) => response.json())
+ .then((data) => { if (!cancelled) setBetaState(data); })
+ .catch(() => { if (!cancelled) setBetaState(null); });
+ return () => { cancelled = true; };
+ }, [open]);
+
+ if (!open) return null;
+
+ const createVault = async () => {
+ onStateChange("syncing");
+ setMessage("");
+ try {
+ const data = await readJson(await fetch("/api/vault", {
+ method: "POST",
+ credentials: "same-origin",
+ headers: { "Content-Type": "application/json" },
+ body: JSON.stringify({
+ action: "create",
+ profile,
+ position,
+ locale,
+ debts,
+ discoveryConsent,
+ inviteCode,
+ betaConsent,
+ }),
+ }));
+ if (!data.vault || !data.recoveryCode) throw new Error("Missing vault response");
+ setFreshCode(data.recoveryCode);
+ onRestore(data.vault);
+ onStateChange("synced");
+ } catch (error) {
+ setMessage(error instanceof Error ? error.message : t.error);
+ onStateChange("error");
+ }
+ };
+
+ const recoverVault = async () => {
+ if (!recoveryInput.trim()) return;
+ onStateChange("syncing");
+ setMessage("");
+ try {
+ const data = await readJson(await fetch("/api/vault", {
+ method: "POST",
+ credentials: "same-origin",
+ headers: { "Content-Type": "application/json" },
+ body: JSON.stringify({ action: "recover", recoveryCode: recoveryInput }),
+ }));
+ if (!data.vault) throw new Error("Missing vault response");
+ onRestore(data.vault);
+ setRecoveryInput("");
+ onStateChange("synced");
+ } catch (error) {
+ setMessage(error instanceof Error ? error.message : t.error);
+ onStateChange("local");
+ }
+ };
+
+ const rotateCode = async () => {
+ onStateChange("syncing");
+ setMessage("");
+ try {
+ const data = await readJson(await fetch("/api/vault", {
+ method: "POST",
+ credentials: "same-origin",
+ headers: { "Content-Type": "application/json" },
+ body: JSON.stringify({ action: "rotate" }),
+ }));
+ if (!data.recoveryCode) throw new Error("Missing recovery code");
+ setFreshCode(data.recoveryCode);
+ onStateChange("synced");
+ } catch (error) {
+ setMessage(error instanceof Error ? error.message : t.error);
+ onStateChange("error");
+ }
+ };
+
+ const retry = async () => {
+ onStateChange("checking");
+ setMessage("");
+ try {
+ const update = await fetch("/api/vault", {
+ method: "PATCH",
+ credentials: "same-origin",
+ headers: { "Content-Type": "application/json" },
+ body: JSON.stringify({ profile, position, locale, discoveryConsent }),
+ });
+ if (!update.ok && update.status !== 401) {
+ await readJson(update);
+ }
+ const data = await readJson(await fetch("/api/vault", {
+ credentials: "same-origin",
+ cache: "no-store",
+ }));
+ if (!data.vault) throw new Error("Missing vault response");
+ onRestore(data.vault);
+ onStateChange("synced");
+ } catch {
+ onStateChange("local");
+ }
+ };
+
+ const exportLocal = () => {
+ const blob = new Blob([
+ JSON.stringify({ exportedAt: new Date().toISOString(), profile, position, debts, discoveryConsent }, null, 2),
+ ], { type: "application/json" });
+ const url = URL.createObjectURL(blob);
+ const anchor = document.createElement("a");
+ anchor.href = url;
+ anchor.download = "debt-world-local-export.json";
+ anchor.click();
+ URL.revokeObjectURL(url);
+ };
+
+ const deleteVault = async () => {
+ if (deleteInput !== "DELETE") return;
+ onStateChange("syncing");
+ setMessage("");
+ try {
+ await readJson(await fetch("/api/vault", {
+ method: "DELETE",
+ credentials: "same-origin",
+ headers: { "Content-Type": "application/json" },
+ body: JSON.stringify({ confirm: "DELETE" }),
+ }));
+ setFreshCode("");
+ setDeleteInput("");
+ onDeleted();
+ onStateChange("local");
+ onClose();
+ } catch (error) {
+ setMessage(error instanceof Error ? error.message : t.error);
+ onStateChange("error");
+ }
+ };
+
+ const copyCode = async () => {
+ await navigator.clipboard.writeText(freshCode);
+ setCopied(true);
+ window.setTimeout(() => setCopied(false), 1500);
+ };
+
+ return (
+
+
event.stopPropagation()}>
+ ×
+ CLOUD VAULT · PUBLIC BETA
+ {t.title}
+
+
+ onDiscoveryConsentChange(event.target.checked)}
+ />
+ {t.discoveryTitle} {t.discoveryBody}
{t.discoveryOff}
+
+ ◇ {locale === "zh" ? "查看完整隐私说明、数据权利与删除流程" : "Read the full privacy notice, data controls, and deletion flow"} ↗
+
+ {cloudState !== "synced" && !freshCode ? (
+ <>
+
+
{t.localTitle}
+
{t.localBody}
+
+ {betaState?.inviteRequired &&
+
{t.inviteTitle}
+
{t.inviteBody}
+
setInviteCode(event.target.value.toUpperCase())} placeholder={t.invitePlaceholder} autoCapitalize="characters" autoComplete="off"/>
+
setBetaConsent(event.target.checked)}/>{t.betaConsent}
+
}
+ {betaState && !betaState.signupsEnabled && ⌁ {t.signupsPaused}
}
+
+ {busy ? t.working : t.create}
+
+ {t.recoverTitle}
+
+ setRecoveryInput(event.target.value)}
+ placeholder={t.recoverPlaceholder}
+ autoCapitalize="characters"
+ autoComplete="off"
+ />
+
+
+ {t.recover}
+
+ {t.exportLocal}
+ {cloudState === "error" && {t.retry} }
+ >
+ ) : (
+ <>
+
+ {freshCode && (
+
+
{t.freshTitle}
+
{t.freshBody}
+
{freshCode}
+
{copied ? t.copied : t.copy}
+
+ )}
+
+
+
{t.deleteTitle}
+
{t.deleteBody}
+
setDeleteInput(event.target.value)} placeholder="DELETE" />
+
{t.delete}
+
+ >
+ )}
+
+ {message && {message}
}
+
+
+ );
+}
diff --git a/app/about/page.tsx b/app/about/page.tsx
new file mode 100644
index 0000000..a9d3944
--- /dev/null
+++ b/app/about/page.tsx
@@ -0,0 +1,10 @@
+import type { Metadata } from "next";
+import AboutPage from "../AboutPage";
+
+export const metadata: Metadata = {
+ title: "上岸星球是什么 — 真实、匿名、共同生长的债务世界",
+ description: "了解上岸星球如何整理房贷、信用卡、学贷与更多债务,让还款进度跟随现实,并通过匿名数据形成全球债务地图。",
+ alternates: { canonical: "/about", languages: { "zh-CN": "/about", en: "/en/about" } },
+};
+
+export default function Page() { return
; }
diff --git a/app/admin/page.tsx b/app/admin/page.tsx
new file mode 100644
index 0000000..95d1c5f
--- /dev/null
+++ b/app/admin/page.tsx
@@ -0,0 +1,9 @@
+import { chatGPTSignOutPath, requireChatGPTUser } from "@/app/chatgpt-auth";
+import OwnerAdminDashboard from "@/app/OwnerAdminDashboard";
+
+export const dynamic = "force-dynamic";
+
+export default async function AdminPage() {
+ const user = await requireChatGPTUser("/admin");
+ return
;
+}
diff --git a/app/api/account/route.ts b/app/api/account/route.ts
new file mode 100644
index 0000000..77fa134
--- /dev/null
+++ b/app/api/account/route.ts
@@ -0,0 +1,127 @@
+import { getD1 } from "@/db";
+import {
+ accountHasVault,
+ clearAccountSession,
+ getAccount,
+ loginAccount,
+ publicAccount,
+ registerAccount,
+ requireAccount,
+ withAccountSession,
+} from "@/lib/account-server";
+import {
+ HttpError,
+ SESSION_COOKIE,
+ assertSameOrigin,
+ ensureAccountWorld,
+ hashRecoveryCode,
+ noStoreJson,
+ normalizeRecoveryCode,
+ routeError,
+ withSessionCookie,
+} from "@/lib/vault-server";
+import { verifyTurnstileToken } from "@/lib/turnstile-server";
+import { assertAccountSignupOpen } from "@/lib/beta-server";
+import { attachReferral } from "@/lib/referral-server";
+
+export const dynamic = "force-dynamic";
+
+function cookieValue(request: Request, name: string) {
+ const source = request.headers.get("Cookie") ?? "";
+ for (const part of source.split(";")) {
+ const [key, ...rest] = part.trim().split("=");
+ if (key === name) return decodeURIComponent(rest.join("="));
+ }
+ return "";
+}
+
+async function unclaimedVaultFromCode(value: unknown) {
+ const code = normalizeRecoveryCode(value);
+ if (code.length !== 26 || !code.startsWith("DW")) return null;
+ const recoveryHash = await hashRecoveryCode(code);
+ const vault = await getD1().prepare(
+ `SELECT v.id FROM vaults v
+ LEFT JOIN account_vaults av ON av.vault_id = v.id
+ WHERE v.recovery_hash = ?1 AND av.vault_id IS NULL LIMIT 1`,
+ ).bind(recoveryHash).first<{ id: string }>();
+ return vault ? { id: vault.id, code } : null;
+}
+
+async function accountState(request: Request) {
+ const account = await getAccount(request);
+ if (!account) return { authenticated: false as const };
+ await ensureAccountWorld(account.id);
+ return {
+ authenticated: true as const,
+ account: publicAccount(account, true),
+ legacyVaultDetected: false,
+ };
+}
+
+export async function GET(request: Request) {
+ try {
+ return noStoreJson(await accountState(request));
+ } catch (error) {
+ return routeError(error);
+ }
+}
+
+export async function POST(request: Request) {
+ try {
+ assertSameOrigin(request);
+ const payload = await request.json() as {
+ action?: "register" | "login" | "logout" | "claim_legacy" | "link_vault";
+ username?: string;
+ password?: string;
+ recoveryCode?: string;
+ turnstileToken?: string;
+ signupSource?: string;
+ referralCode?: string;
+ };
+
+ if (payload.action === "logout") {
+ return clearAccountSession(noStoreJson({ authenticated: false }), request);
+ }
+
+ if (payload.action === "register" || payload.action === "login") {
+ if (payload.action === "register") {
+ await assertAccountSignupOpen();
+ await verifyTurnstileToken(request, payload.turnstileToken, "register");
+ }
+ const result = payload.action === "register"
+ ? await registerAccount(request, payload.username, payload.password, payload.signupSource)
+ : await loginAccount(request, payload.username, payload.password);
+ const world = await ensureAccountWorld(result.account.id);
+ if (payload.action === "register" && payload.referralCode) await attachReferral(world.id, payload.referralCode);
+ const response = noStoreJson({
+ authenticated: true,
+ account: publicAccount(result.account, true),
+ legacyVaultDetected: false,
+ }, { status: payload.action === "register" ? 201 : 200 });
+ return withAccountSession(response, request, result.rawToken);
+ }
+
+ if (payload.action === "claim_legacy" || payload.action === "link_vault") {
+ const account = await requireAccount(request);
+ if (await accountHasVault(account.id)) throw new HttpError(409, "This account already has a linked world.");
+ const sourceCode = payload.action === "link_vault"
+ ? payload.recoveryCode
+ : cookieValue(request, SESSION_COOKIE);
+ const vault = await unclaimedVaultFromCode(sourceCode);
+ if (!vault) throw new HttpError(404, "No unclaimed world matched that recovery code.");
+ await getD1().prepare(
+ "INSERT INTO account_vaults (account_id, vault_id) VALUES (?1, ?2)",
+ ).bind(account.id, vault.id).run();
+ const response = noStoreJson({
+ authenticated: true,
+ account: publicAccount(account, true),
+ legacyVaultDetected: false,
+ });
+ return withSessionCookie(response, request, vault.code);
+ }
+
+ throw new HttpError(400, "A valid account action is required.");
+ } catch (error) {
+ return routeError(error);
+ }
+}
diff --git a/app/api/admin/beta/route.ts b/app/api/admin/beta/route.ts
new file mode 100644
index 0000000..e9be05e
--- /dev/null
+++ b/app/api/admin/beta/route.ts
@@ -0,0 +1,294 @@
+import { getD1 } from "@/db";
+import { ensureAccountSignupSourceSchema, sha256Hex } from "@/lib/account-server";
+import { betaPublicState } from "@/lib/beta-server";
+import { requireCommunityAdmin } from "@/lib/community-safety";
+import { HttpError, assertSameOrigin, cleanText, noStoreJson, routeError } from "@/lib/vault-server";
+
+export const dynamic = "force-dynamic";
+
+async function betaAdminState() {
+ const db = getD1();
+ await ensureAccountSignupSourceSchema();
+ const publicState = await betaPublicState();
+ const [metrics, counters, accounts, sources, legacyVaults, feedback, trafficDaily] = await Promise.all([
+ db.prepare(
+ `SELECT
+ (SELECT COUNT(*) FROM vaults) AS vaults,
+ (SELECT COUNT(*) FROM accounts) AS accounts,
+ (SELECT COUNT(*) FROM accounts WHERE status = 'active') AS active_accounts,
+ (SELECT COUNT(*) FROM accounts WHERE status = 'suspended') AS suspended_accounts,
+ (SELECT COUNT(*) FROM accounts WHERE status = 'active' AND datetime(COALESCE(last_seen_at, created_at)) >= datetime('now', '-1 day')) AS active_24h,
+ (SELECT COUNT(*) FROM accounts WHERE status = 'active' AND datetime(COALESCE(last_seen_at, created_at)) >= datetime('now', '-7 days')) AS active_7d,
+ (SELECT COUNT(*) FROM debts) AS debts,
+ (SELECT COUNT(*) FROM payment_records) AS payments,
+ (SELECT COALESCE(SUM(request_count), 0) FROM ai_daily_usage) AS ai_requests,
+ (SELECT COUNT(*) FROM public_stories WHERE status IN ('pending', 'review')) AS pending_stories,
+ (SELECT COUNT(*) FROM public_stories WHERE status = 'published') AS published_stories,
+ (SELECT COUNT(*) FROM story_reports WHERE status = 'open') AS open_reports,
+ (SELECT COUNT(*) FROM beta_enrollments) AS enrolled,
+ (SELECT COUNT(*) FROM beta_feedback WHERE status = 'open') AS open_feedback,
+ (SELECT COUNT(*) FROM site_daily_visitors WHERE visit_date = date('now')) AS visitors_today,
+ (SELECT COALESCE(SUM(page_views), 0) FROM site_daily_visitors WHERE visit_date = date('now')) AS page_views_today,
+ (SELECT COUNT(*) FROM referral_relationships) AS referral_invites,
+ (SELECT COUNT(*) FROM referral_relationships WHERE status = 'rewarded') AS referral_activated,
+ (SELECT COUNT(*) FROM referral_relationships WHERE status = 'pending') AS referral_pending`,
+ ).first<{
+ vaults: number; accounts: number; active_accounts: number; suspended_accounts: number; active_24h: number; active_7d: number;
+ debts: number; payments: number; ai_requests: number; pending_stories: number; published_stories: number; open_reports: number;
+ enrolled: number; open_feedback: number; visitors_today: number; page_views_today: number;
+ referral_invites: number; referral_activated: number; referral_pending: number;
+ }>(),
+ db.prepare("SELECT uses, max_uses, updated_at FROM beta_invite_counters ORDER BY updated_at DESC LIMIT 1").first<{ uses: number; max_uses: number; updated_at: string }>(),
+ db.prepare(
+ `SELECT a.user_code, a.username, a.status AS login_status, a.signup_source, a.created_at, a.last_login_at, a.last_seen_at,
+ v.id AS vault_id, v.country_code, v.created_at AS vault_created_at, v.updated_at AS vault_updated_at,
+ COALESCE(dc.debt_count, 0) AS debt_count,
+ COALESCE(pc.payment_count, 0) AS payment_count,
+ COALESCE(aic.ai_count, 0) AS ai_count,
+ COALESCE(fc.feedback_count, 0) AS feedback_count,
+ COALESCE(sc.story_count, 0) AS story_count
+ FROM accounts a
+ LEFT JOIN account_vaults av ON av.account_id = a.id
+ LEFT JOIN vaults v ON v.id = av.vault_id
+ LEFT JOIN (SELECT vault_id, COUNT(*) AS debt_count FROM debts GROUP BY vault_id) dc ON dc.vault_id = v.id
+ LEFT JOIN (SELECT vault_id, COUNT(*) AS payment_count FROM payment_records GROUP BY vault_id) pc ON pc.vault_id = v.id
+ LEFT JOIN (SELECT vault_id, SUM(request_count) AS ai_count FROM ai_daily_usage GROUP BY vault_id) aic ON aic.vault_id = v.id
+ LEFT JOIN (SELECT vault_id, COUNT(*) AS feedback_count FROM beta_feedback GROUP BY vault_id) fc ON fc.vault_id = v.id
+ LEFT JOIN (SELECT vault_id, COUNT(*) AS story_count FROM public_stories GROUP BY vault_id) sc ON sc.vault_id = v.id
+ ORDER BY COALESCE(a.last_seen_at, a.created_at) DESC LIMIT 300`,
+ ).all<{
+ user_code: string; username: string; login_status: string; signup_source: string; created_at: string; last_login_at: string | null; last_seen_at: string | null;
+ vault_id: string | null; country_code: string | null; vault_created_at: string | null; vault_updated_at: string | null;
+ debt_count: number; payment_count: number; ai_count: number; feedback_count: number; story_count: number;
+ }>(),
+ db.prepare(
+ `SELECT COALESCE(NULLIF(a.signup_source, ''), 'direct') AS source,
+ COUNT(*) AS account_count,
+ SUM(CASE WHEN av.vault_id IS NOT NULL THEN 1 ELSE 0 END) AS linked_count,
+ SUM(CASE WHEN dc.debt_count > 0 THEN 1 ELSE 0 END) AS debt_count,
+ SUM(CASE WHEN fc.feedback_count > 0 THEN 1 ELSE 0 END) AS feedback_count
+ FROM accounts a LEFT JOIN account_vaults av ON av.account_id = a.id
+ LEFT JOIN (SELECT vault_id, COUNT(*) AS debt_count FROM debts GROUP BY vault_id) dc ON dc.vault_id = av.vault_id
+ LEFT JOIN (SELECT vault_id, COUNT(*) AS feedback_count FROM beta_feedback GROUP BY vault_id) fc ON fc.vault_id = av.vault_id
+ GROUP BY COALESCE(NULLIF(a.signup_source, ''), 'direct')
+ ORDER BY account_count DESC, source ASC LIMIT 20`,
+ ).all<{ source: string; account_count: number; linked_count: number; debt_count: number; feedback_count: number }>(),
+ db.prepare(
+ `SELECT v.id AS vault_id, v.country_code, v.created_at, v.updated_at,
+ COALESCE(dc.debt_count, 0) AS debt_count,
+ COALESCE(pc.payment_count, 0) AS payment_count,
+ COALESCE(aic.ai_count, 0) AS ai_count,
+ COALESCE(fc.feedback_count, 0) AS feedback_count,
+ COALESCE(sc.story_count, 0) AS story_count
+ FROM vaults v LEFT JOIN account_vaults av ON av.vault_id = v.id
+ LEFT JOIN (SELECT vault_id, COUNT(*) AS debt_count FROM debts GROUP BY vault_id) dc ON dc.vault_id = v.id
+ LEFT JOIN (SELECT vault_id, COUNT(*) AS payment_count FROM payment_records GROUP BY vault_id) pc ON pc.vault_id = v.id
+ LEFT JOIN (SELECT vault_id, SUM(request_count) AS ai_count FROM ai_daily_usage GROUP BY vault_id) aic ON aic.vault_id = v.id
+ LEFT JOIN (SELECT vault_id, COUNT(*) AS feedback_count FROM beta_feedback GROUP BY vault_id) fc ON fc.vault_id = v.id
+ LEFT JOIN (SELECT vault_id, COUNT(*) AS story_count FROM public_stories GROUP BY vault_id) sc ON sc.vault_id = v.id
+ WHERE av.vault_id IS NULL ORDER BY v.updated_at DESC LIMIT 300`,
+ ).all<{
+ vault_id: string; country_code: string; created_at: string; updated_at: string;
+ debt_count: number; payment_count: number; ai_count: number; feedback_count: number; story_count: number;
+ }>(),
+ db.prepare(
+ `SELECT bf.id, bf.vault_id, bf.category, bf.rating, bf.message, bf.page_path, bf.status, bf.created_at,
+ a.user_code, a.username
+ FROM beta_feedback bf
+ LEFT JOIN account_vaults av ON av.vault_id = bf.vault_id
+ LEFT JOIN accounts a ON a.id = av.account_id
+ ORDER BY bf.created_at DESC LIMIT 100`,
+ ).all<{ id: string; vault_id: string; category: string; rating: number; message: string; page_path: string; status: string; created_at: string; user_code: string | null; username: string | null }>(),
+ db.prepare(
+ `WITH RECURSIVE days(day) AS (
+ SELECT date('now', '-13 days')
+ UNION ALL SELECT date(day, '+1 day') FROM days WHERE day < date('now')
+ ), visitors AS (
+ SELECT visit_date AS day, COUNT(*) AS unique_visitors, SUM(page_views) AS page_views
+ FROM site_daily_visitors WHERE visit_date >= date('now', '-13 days') GROUP BY visit_date
+ ), registrations AS (
+ SELECT date(created_at) AS day, COUNT(*) AS registrations
+ FROM accounts WHERE date(created_at) >= date('now', '-13 days') GROUP BY date(created_at)
+ ), activations AS (
+ SELECT date(created_at) AS day, COUNT(DISTINCT vault_id) AS debt_activations
+ FROM debts WHERE date(created_at) >= date('now', '-13 days') GROUP BY date(created_at)
+ ), referrals AS (
+ SELECT date(COALESCE(qualified_at, rewarded_at)) AS day, COUNT(*) AS referral_activations
+ FROM referral_relationships WHERE status = 'rewarded' AND date(COALESCE(qualified_at, rewarded_at)) >= date('now', '-13 days')
+ GROUP BY date(COALESCE(qualified_at, rewarded_at))
+ )
+ SELECT days.day,
+ COALESCE(visitors.unique_visitors, 0) AS unique_visitors,
+ COALESCE(visitors.page_views, 0) AS page_views,
+ COALESCE(registrations.registrations, 0) AS registrations,
+ COALESCE(activations.debt_activations, 0) AS debt_activations,
+ COALESCE(referrals.referral_activations, 0) AS referral_activations
+ FROM days
+ LEFT JOIN visitors ON visitors.day = days.day
+ LEFT JOIN registrations ON registrations.day = days.day
+ LEFT JOIN activations ON activations.day = days.day
+ LEFT JOIN referrals ON referrals.day = days.day
+ ORDER BY days.day ASC`,
+ ).all<{ day: string; unique_visitors: number; page_views: number; registrations: number; debt_activations: number; referral_activations: number }>(),
+ ]);
+ const legacyCodes = new Map();
+ await Promise.all(legacyVaults.results.map(async (item) => {
+ legacyCodes.set(item.vault_id, `LEGACY-${(await sha256Hex(item.vault_id)).slice(0, 8).toUpperCase()}`);
+ }));
+ const testers = [
+ ...accounts.results.map((item) => ({
+ testerCode: item.user_code,
+ username: item.username,
+ loginStatus: item.login_status === "suspended" ? "suspended" : "active",
+ signupSource: item.signup_source || "direct",
+ accountStatus: item.vault_id ? "linked" : "account_only",
+ countryCode: item.country_code ?? "",
+ joinedAt: item.created_at,
+ lastLoginAt: item.last_login_at,
+ lastActiveAt: [item.last_seen_at, item.vault_updated_at].filter(Boolean).sort().at(-1) ?? item.created_at,
+ vaultCreatedAt: item.vault_created_at,
+ debtCount: Number(item.debt_count ?? 0),
+ paymentCount: Number(item.payment_count ?? 0),
+ aiCount: Number(item.ai_count ?? 0),
+ feedbackCount: Number(item.feedback_count ?? 0),
+ storyCount: Number(item.story_count ?? 0),
+ })),
+ ...legacyVaults.results.map((item) => ({
+ testerCode: legacyCodes.get(item.vault_id)!,
+ username: null,
+ loginStatus: "legacy" as const,
+ signupSource: "legacy",
+ accountStatus: "legacy" as const,
+ countryCode: item.country_code,
+ joinedAt: item.created_at,
+ lastLoginAt: null,
+ lastActiveAt: item.updated_at,
+ vaultCreatedAt: item.created_at,
+ debtCount: Number(item.debt_count ?? 0),
+ paymentCount: Number(item.payment_count ?? 0),
+ aiCount: Number(item.ai_count ?? 0),
+ feedbackCount: Number(item.feedback_count ?? 0),
+ storyCount: Number(item.story_count ?? 0),
+ })),
+ ].sort((left, right) => String(right.lastActiveAt).localeCompare(String(left.lastActiveAt)));
+ return {
+ config: {
+ signupsEnabled: publicState.signupsEnabled,
+ inviteRequired: publicState.inviteRequired,
+ inviteConfigured: publicState.inviteConfigured,
+ maxUses: publicState.maxUses,
+ dailySignupLimit: publicState.dailySignupLimit,
+ signupsToday: publicState.signupsToday,
+ },
+ counts: {
+ accounts: Number(metrics?.accounts ?? 0),
+ activeAccounts: Number(metrics?.active_accounts ?? 0),
+ suspendedAccounts: Number(metrics?.suspended_accounts ?? 0),
+ active24h: Number(metrics?.active_24h ?? 0),
+ active7d: Number(metrics?.active_7d ?? 0),
+ vaults: Number(metrics?.vaults ?? 0),
+ debts: Number(metrics?.debts ?? 0),
+ payments: Number(metrics?.payments ?? 0),
+ aiRequests: Number(metrics?.ai_requests ?? 0),
+ pendingStories: Number(metrics?.pending_stories ?? 0),
+ publishedStories: Number(metrics?.published_stories ?? 0),
+ openReports: Number(metrics?.open_reports ?? 0),
+ legacyVaults: legacyVaults.results.length,
+ enrolled: Number(metrics?.enrolled ?? 0),
+ openFeedback: Number(metrics?.open_feedback ?? 0),
+ inviteUses: Number(counters?.uses ?? 0),
+ inviteLimit: Number(counters?.max_uses ?? publicState.maxUses),
+ visitorsToday: Number(metrics?.visitors_today ?? 0),
+ pageViewsToday: Number(metrics?.page_views_today ?? 0),
+ referralInvites: Number(metrics?.referral_invites ?? 0),
+ referralActivated: Number(metrics?.referral_activated ?? 0),
+ referralPending: Number(metrics?.referral_pending ?? 0),
+ },
+ testers,
+ sources: sources.results.map((item) => ({
+ source: item.source,
+ accounts: Number(item.account_count ?? 0),
+ linked: Number(item.linked_count ?? 0),
+ withDebt: Number(item.debt_count ?? 0),
+ withFeedback: Number(item.feedback_count ?? 0),
+ })),
+ trafficDaily: trafficDaily.results.map((item) => ({
+ day: item.day,
+ uniqueVisitors: Number(item.unique_visitors ?? 0),
+ pageViews: Number(item.page_views ?? 0),
+ registrations: Number(item.registrations ?? 0),
+ debtActivations: Number(item.debt_activations ?? 0),
+ referralActivations: Number(item.referral_activations ?? 0),
+ })),
+ feedback: feedback.results.map((item) => ({
+ id: item.id,
+ testerCode: item.user_code ?? legacyCodes.get(item.vault_id) ?? "LEGACY",
+ username: item.username,
+ category: item.category,
+ rating: item.rating,
+ message: item.message,
+ pagePath: item.page_path,
+ status: item.status,
+ createdAt: item.created_at,
+ })),
+ };
+}
+
+export async function GET(request: Request) {
+ try {
+ await requireCommunityAdmin(request);
+ return noStoreJson(await betaAdminState());
+ } catch (error) {
+ return routeError(error);
+ }
+}
+
+export async function POST(request: Request) {
+ try {
+ assertSameOrigin(request);
+ const admin = await requireCommunityAdmin(request);
+ const payload = await request.json() as { action?: string; enabled?: boolean; feedbackId?: string; testerCode?: string; accountStatus?: string };
+ const db = getD1();
+ if (payload.action === "set_signups") {
+ if (typeof payload.enabled !== "boolean") throw new HttpError(400, "A signup state is required.");
+ await db.prepare(
+ `INSERT INTO beta_runtime_settings (id, signups_enabled, updated_by_digest, updated_at)
+ VALUES ('default', ?1, ?2, CURRENT_TIMESTAMP)
+ ON CONFLICT(id) DO UPDATE SET signups_enabled = excluded.signups_enabled,
+ updated_by_digest = excluded.updated_by_digest, updated_at = CURRENT_TIMESTAMP`,
+ ).bind(payload.enabled ? 1 : 0, admin.actorDigest).run();
+ } else if (payload.action === "resolve_feedback") {
+ const feedbackId = cleanText(payload.feedbackId, 80);
+ if (!feedbackId) throw new HttpError(400, "Feedback id is required.");
+ const updated = await db.prepare(
+ `UPDATE beta_feedback SET status = 'resolved', resolved_at = CURRENT_TIMESTAMP
+ WHERE id = ?1 AND status = 'open'`,
+ ).bind(feedbackId).run();
+ if (Number(updated.meta?.changes ?? 0) < 1) throw new HttpError(404, "Open feedback was not found.");
+ } else if (payload.action === "reopen_feedback") {
+ const feedbackId = cleanText(payload.feedbackId, 80);
+ if (!feedbackId) throw new HttpError(400, "Feedback id is required.");
+ const updated = await db.prepare(
+ `UPDATE beta_feedback SET status = 'open', resolved_at = NULL
+ WHERE id = ?1 AND status = 'resolved'`,
+ ).bind(feedbackId).run();
+ if (Number(updated.meta?.changes ?? 0) < 1) throw new HttpError(404, "Resolved feedback was not found.");
+ } else if (payload.action === "set_account_status") {
+ const testerCode = cleanText(payload.testerCode, 40).toUpperCase();
+ const accountStatus = payload.accountStatus === "active" ? "active" : payload.accountStatus === "suspended" ? "suspended" : "";
+ if (!testerCode || !accountStatus) throw new HttpError(400, "A user and valid account status are required.");
+ const account = await db.prepare("SELECT id, status FROM accounts WHERE user_code = ?1 LIMIT 1").bind(testerCode).first<{ id: string; status: string }>();
+ if (!account) throw new HttpError(404, "Account was not found.");
+ if (account.status !== accountStatus) {
+ const statements = [db.prepare("UPDATE accounts SET status = ?1, updated_at = CURRENT_TIMESTAMP WHERE id = ?2").bind(accountStatus, account.id)];
+ if (accountStatus === "suspended") statements.push(db.prepare("DELETE FROM account_sessions WHERE account_id = ?1").bind(account.id));
+ await db.batch(statements);
+ }
+ } else {
+ throw new HttpError(400, "A valid beta admin action is required.");
+ }
+ return noStoreJson(await betaAdminState());
+ } catch (error) {
+ return routeError(error);
+ }
+}
diff --git a/app/api/admin/community/route.ts b/app/api/admin/community/route.ts
new file mode 100644
index 0000000..2150559
--- /dev/null
+++ b/app/api/admin/community/route.ts
@@ -0,0 +1,166 @@
+import { getD1 } from "@/db";
+import { cleanModerationNote, requireCommunityAdmin } from "@/lib/community-safety";
+import { HttpError, assertSameOrigin, cleanText, noStoreJson, routeError } from "@/lib/vault-server";
+
+export const dynamic = "force-dynamic";
+
+type ModerationStoryRow = {
+ id: string;
+ anonymous_name: string;
+ country_code: string;
+ debt_kind: string;
+ amount_band: string;
+ currency: string;
+ repayment_approach: string;
+ story_text: string;
+ status: string;
+ created_at: string;
+ open_report_count: number;
+ encouragement_count: number;
+};
+
+const transitions = {
+ approve: "published",
+ reject: "rejected",
+ hide: "hidden",
+ restore: "published",
+} as const;
+
+function moderationStory(row: ModerationStoryRow) {
+ return {
+ id: row.id,
+ anonymousName: row.anonymous_name,
+ countryCode: row.country_code,
+ debtKind: row.debt_kind,
+ amountBand: row.amount_band,
+ currency: row.currency,
+ repaymentApproach: row.repayment_approach,
+ storyText: row.story_text,
+ status: row.status,
+ createdAt: row.created_at,
+ openReportCount: Number(row.open_report_count ?? 0),
+ encouragementCount: Number(row.encouragement_count ?? 0),
+ };
+}
+
+async function moderationCounts() {
+ const db = getD1();
+ const [statusRows, reportRow] = await Promise.all([
+ db.prepare("SELECT status, COUNT(*) AS count FROM public_stories GROUP BY status").all<{ status: string; count: number }>(),
+ db.prepare("SELECT COUNT(*) AS count FROM story_reports WHERE status = 'open'").first<{ count: number }>(),
+ ]);
+ const statuses = Object.fromEntries(statusRows.results.map((row) => [row.status, Number(row.count)]));
+ return {
+ pending: statuses.pending ?? 0,
+ review: statuses.review ?? 0,
+ published: statuses.published ?? 0,
+ hidden: statuses.hidden ?? 0,
+ rejected: statuses.rejected ?? 0,
+ openReports: Number(reportRow?.count ?? 0),
+ };
+}
+
+export async function GET(request: Request) {
+ try {
+ await requireCommunityAdmin(request);
+ const counts = await moderationCounts();
+ if (new URL(request.url).searchParams.get("summary") === "1") {
+ return noStoreJson({ authorized: true, counts });
+ }
+ const db = getD1();
+ const [storiesResult, reportsResult, actionsResult] = await Promise.all([
+ db.prepare(
+ `SELECT s.*,
+ (SELECT COUNT(*) FROM story_reports r WHERE r.story_id = s.id AND r.status = 'open') AS open_report_count,
+ (SELECT COUNT(*) FROM story_encouragements e WHERE e.story_id = s.id) AS encouragement_count
+ FROM public_stories s
+ WHERE s.status != 'published'
+ OR EXISTS (SELECT 1 FROM story_reports r WHERE r.story_id = s.id AND r.status = 'open')
+ ORDER BY CASE s.status WHEN 'review' THEN 0 WHEN 'pending' THEN 1 WHEN 'hidden' THEN 2 WHEN 'rejected' THEN 3 ELSE 4 END,
+ s.updated_at DESC
+ LIMIT 100`,
+ ).all(),
+ db.prepare(
+ `SELECT r.id, r.story_id, r.reason, r.details, r.created_at,
+ s.anonymous_name, s.status AS story_status
+ FROM story_reports r
+ JOIN public_stories s ON s.id = r.story_id
+ WHERE r.status = 'open'
+ ORDER BY r.created_at ASC
+ LIMIT 100`,
+ ).all<{ id: string; story_id: string; reason: string; details: string; created_at: string; anonymous_name: string; story_status: string }>(),
+ db.prepare(
+ `SELECT a.id, a.story_id, a.action, a.from_status, a.to_status, a.note, a.created_at,
+ s.anonymous_name
+ FROM community_moderation_actions a
+ JOIN public_stories s ON s.id = a.story_id
+ ORDER BY a.created_at DESC
+ LIMIT 30`,
+ ).all<{ id: string; story_id: string; action: string; from_status: string; to_status: string; note: string; created_at: string; anonymous_name: string }>(),
+ ]);
+ return noStoreJson({
+ authorized: true,
+ counts,
+ stories: storiesResult.results.map(moderationStory),
+ reports: reportsResult.results.map((row) => ({
+ id: row.id,
+ storyId: row.story_id,
+ reason: row.reason,
+ details: row.details,
+ createdAt: row.created_at,
+ anonymousName: row.anonymous_name,
+ storyStatus: row.story_status,
+ })),
+ actions: actionsResult.results.map((row) => ({
+ id: row.id,
+ storyId: row.story_id,
+ anonymousName: row.anonymous_name,
+ action: row.action,
+ fromStatus: row.from_status,
+ toStatus: row.to_status,
+ note: row.note,
+ createdAt: row.created_at,
+ })),
+ });
+ } catch (error) {
+ return routeError(error);
+ }
+}
+
+export async function POST(request: Request) {
+ try {
+ assertSameOrigin(request);
+ const admin = await requireCommunityAdmin(request);
+ const payload = await request.json() as { storyId?: string; action?: keyof typeof transitions; note?: string };
+ const storyId = cleanText(payload.storyId, 80);
+ const action = payload.action;
+ if (!storyId || !action || !(action in transitions)) throw new HttpError(400, "A valid moderation action is required.");
+ const db = getD1();
+ const story = await db.prepare(
+ "SELECT id, status FROM public_stories WHERE id = ?1 LIMIT 1",
+ ).bind(storyId).first<{ id: string; status: string }>();
+ if (!story) throw new HttpError(404, "Story not found.");
+ const nextStatus = transitions[action];
+ if (story.status === nextStatus) throw new HttpError(409, "The story is already in that state.");
+ const note = cleanModerationNote(payload.note);
+ if ((action === "reject" || action === "hide") && note.length < 4) {
+ throw new HttpError(400, "Add a short moderation reason before rejecting or hiding a story.");
+ }
+ await db.batch([
+ db.prepare(
+ "UPDATE public_stories SET status = ?1, updated_at = CURRENT_TIMESTAMP WHERE id = ?2",
+ ).bind(nextStatus, story.id),
+ db.prepare(
+ "UPDATE story_reports SET status = 'resolved', resolved_at = CURRENT_TIMESTAMP WHERE story_id = ?1 AND status = 'open'",
+ ).bind(story.id),
+ db.prepare(
+ `INSERT INTO community_moderation_actions
+ (id, story_id, actor_digest, action, from_status, to_status, note)
+ VALUES (?1, ?2, ?3, ?4, ?5, ?6, ?7)`,
+ ).bind(crypto.randomUUID(), story.id, admin.actorDigest, action, story.status, nextStatus, note),
+ ]);
+ return noStoreJson({ storyId: story.id, status: nextStatus, counts: await moderationCounts() });
+ } catch (error) {
+ return routeError(error);
+ }
+}
diff --git a/app/api/admin/session/route.ts b/app/api/admin/session/route.ts
new file mode 100644
index 0000000..cad2316
--- /dev/null
+++ b/app/api/admin/session/route.ts
@@ -0,0 +1,23 @@
+import { ownerAdminSession, registerOwnerAdmin } from "@/lib/community-safety";
+import { HttpError, assertSameOrigin, noStoreJson, routeError } from "@/lib/vault-server";
+
+export const dynamic = "force-dynamic";
+
+export async function GET(request: Request) {
+ try {
+ return noStoreJson(await ownerAdminSession(request));
+ } catch (error) {
+ return routeError(error);
+ }
+}
+
+export async function POST(request: Request) {
+ try {
+ assertSameOrigin(request);
+ const payload = await request.json() as { action?: string };
+ if (payload.action !== "register") throw new HttpError(400, "A valid owner action is required.");
+ return noStoreJson(await registerOwnerAdmin(request), { status: 201 });
+ } catch (error) {
+ return routeError(error);
+ }
+}
diff --git a/app/api/advisor/route.ts b/app/api/advisor/route.ts
new file mode 100644
index 0000000..11e99d9
--- /dev/null
+++ b/app/api/advisor/route.ts
@@ -0,0 +1,31 @@
+import { advisorReadiness, runAdvisor } from "@/lib/advisor-server";
+import type { Locale } from "@/lib/debt-world-types";
+import {
+ HttpError,
+ assertSameOrigin,
+ cleanText,
+ noStoreJson,
+ requireVault,
+ routeError,
+} from "@/lib/vault-server";
+
+export const dynamic = "force-dynamic";
+
+export async function GET() {
+ return noStoreJson(advisorReadiness());
+}
+
+export async function POST(request: Request) {
+ try {
+ assertSameOrigin(request);
+ const vault = await requireVault(request);
+ const body = await request.json() as { message?: unknown; locale?: unknown };
+ const message = cleanText(body.message, 1000);
+ if (!message) throw new HttpError(400, "A question is required.");
+ const locale: Locale = body.locale === "en" ? "en" : "zh";
+ const result = await runAdvisor(vault, message, locale);
+ return noStoreJson(result);
+ } catch (error) {
+ return routeError(error);
+ }
+}
diff --git a/app/api/analytics/route.ts b/app/api/analytics/route.ts
new file mode 100644
index 0000000..1230cbb
--- /dev/null
+++ b/app/api/analytics/route.ts
@@ -0,0 +1,64 @@
+import { getD1 } from "@/db";
+import { assertSameOrigin, cleanText, noStoreJson, routeError } from "@/lib/vault-server";
+
+export const dynamic = "force-dynamic";
+const VISITOR_COOKIE = "dw_visitor";
+
+function readCookie(request: Request, name: string) {
+ const source = request.headers.get("Cookie") ?? "";
+ for (const part of source.split(";")) {
+ const [key, ...rest] = part.trim().split("=");
+ if (key === name) return decodeURIComponent(rest.join("="));
+ }
+ return "";
+}
+
+function newVisitorId() {
+ return Array.from(crypto.getRandomValues(new Uint8Array(16)), (byte) => byte.toString(16).padStart(2, "0")).join("");
+}
+
+async function digest(value: string) {
+ const bytes = await crypto.subtle.digest("SHA-256", new TextEncoder().encode(value));
+ return Array.from(new Uint8Array(bytes), (byte) => byte.toString(16).padStart(2, "0")).join("");
+}
+
+function sourceName(value: unknown) {
+ const source = cleanText(value, 24).toLowerCase().replace(/[^a-z]/g, "");
+ return source || "direct";
+}
+
+function safePath(value: unknown) {
+ const path = cleanText(value, 80).split("?")[0];
+ return /^\/(?:en(?:\/about)?|about|safety|en\/safety)?$/.test(path) ? path || "/" : "/other";
+}
+
+export async function POST(request: Request) {
+ try {
+ assertSameOrigin(request);
+ const payload = await request.json().catch(() => ({})) as { locale?: unknown; source?: unknown; path?: unknown };
+ const visitDate = new Date().toISOString().slice(0, 10);
+ const existing = readCookie(request, VISITOR_COOKIE);
+ const visitorId = /^[a-f0-9]{32}$/.test(existing) ? existing : newVisitorId();
+ const visitorDigest = await digest(`${visitDate}:${visitorId}`);
+ const id = `${visitDate}:${visitorDigest}`;
+ const locale = payload.locale === "en" ? "en" : "zh";
+ const db = getD1();
+ await db.batch([
+ db.prepare(`INSERT INTO site_daily_visitors
+ (id, visit_date, visitor_digest, first_source, first_locale, first_path, page_views)
+ VALUES (?1, ?2, ?3, ?4, ?5, ?6, 1)
+ ON CONFLICT(visit_date, visitor_digest) DO UPDATE SET
+ page_views = MIN(site_daily_visitors.page_views + 1, 1000),
+ last_seen_at = CURRENT_TIMESTAMP`).bind(id, visitDate, visitorDigest, sourceName(payload.source), locale, safePath(payload.path)),
+ db.prepare("DELETE FROM site_daily_visitors WHERE visit_date < date('now', '-90 days')"),
+ ]);
+ const response = noStoreJson({ recorded: true });
+ if (visitorId !== existing) {
+ const secure = new URL(request.url).protocol === "https:" ? "; Secure" : "";
+ response.headers.append("Set-Cookie", `${VISITOR_COOKIE}=${visitorId}; Path=/; HttpOnly; SameSite=Lax; Max-Age=15552000${secure}`);
+ }
+ return response;
+ } catch (error) {
+ return routeError(error);
+ }
+}
diff --git a/app/api/beta/feedback/route.ts b/app/api/beta/feedback/route.ts
new file mode 100644
index 0000000..c4c3f0e
--- /dev/null
+++ b/app/api/beta/feedback/route.ts
@@ -0,0 +1,36 @@
+import { getD1 } from "@/db";
+import { cleanBetaFeedback } from "@/lib/beta-server";
+import { HttpError, assertSameOrigin, cleanNumber, cleanText, noStoreJson, requireVault, routeError } from "@/lib/vault-server";
+
+export const dynamic = "force-dynamic";
+
+const categories = new Set(["confusing", "bug", "helpful", "missing", "safety", "other"]);
+
+export async function POST(request: Request) {
+ try {
+ assertSameOrigin(request);
+ const vault = await requireVault(request);
+ const payload = await request.json() as { category?: string; rating?: number; message?: string; pagePath?: string };
+ const category = categories.has(payload.category ?? "") ? payload.category! : "other";
+ const rating = Math.round(cleanNumber(payload.rating, 1, 5));
+ const message = cleanBetaFeedback(payload.message);
+ if (message.length < 12) throw new HttpError(400, "Add a little more detail so the feedback can be acted on.");
+ const pagePath = cleanText(payload.pagePath, 80, "/").split("?")[0] || "/";
+ const db = getD1();
+ const daily = await db.prepare(
+ `SELECT COUNT(*) AS count FROM beta_feedback
+ WHERE vault_id = ?1 AND created_at >= datetime('now', '-1 day')`,
+ ).bind(vault.id).first<{ count: number }>();
+ if (Number(daily?.count ?? 0) >= 3) {
+ throw new HttpError(429, "Today's feedback limit has been reached. Thank you—please continue tomorrow.");
+ }
+ const id = crypto.randomUUID();
+ await db.prepare(
+ `INSERT INTO beta_feedback (id, vault_id, category, rating, message, page_path)
+ VALUES (?1, ?2, ?3, ?4, ?5, ?6)`,
+ ).bind(id, vault.id, category, rating, message, pagePath).run();
+ return noStoreJson({ id, received: true }, { status: 201 });
+ } catch (error) {
+ return routeError(error);
+ }
+}
diff --git a/app/api/beta/route.ts b/app/api/beta/route.ts
new file mode 100644
index 0000000..f388fc1
--- /dev/null
+++ b/app/api/beta/route.ts
@@ -0,0 +1,21 @@
+import { betaPublicState } from "@/lib/beta-server";
+import { ensureAccountSignupSourceSchema } from "@/lib/account-server";
+import { ensureVaultStorageSchema, noStoreJson, routeError } from "@/lib/vault-server";
+
+export const dynamic = "force-dynamic";
+
+export async function GET() {
+ try {
+ await ensureAccountSignupSourceSchema();
+ await ensureVaultStorageSchema();
+ const state = await betaPublicState();
+ return noStoreJson({
+ signupsEnabled: state.signupsEnabled,
+ accountSignupsEnabled: state.signupsEnabled && state.signupsToday < state.dailySignupLimit,
+ inviteRequired: state.inviteRequired,
+ ready: !state.inviteRequired || state.inviteConfigured,
+ });
+ } catch (error) {
+ return routeError(error);
+ }
+}
diff --git a/app/api/community/route.ts b/app/api/community/route.ts
new file mode 100644
index 0000000..6044158
--- /dev/null
+++ b/app/api/community/route.ts
@@ -0,0 +1,432 @@
+import { getD1 } from "@/db";
+import {
+ HttpError,
+ assertSameOrigin,
+ cleanText,
+ noStoreJson,
+ requireVault,
+ routeError,
+} from "@/lib/vault-server";
+import { consumeCommunityRateLimit } from "@/lib/community-safety";
+import { COMMUNITY_AGE_KEY, COMMUNITY_POLICY_KEY, SAFETY_POLICY_VERSION } from "@/lib/safety-policy";
+import { convertCurrency, fallbackUsdRates } from "@/lib/exchange-rates";
+
+export const dynamic = "force-dynamic";
+
+const reportReasons = new Set([
+ "scam",
+ "harassment",
+ "bad_advice",
+ "identity_exposure",
+ "self_harm",
+ "debt_collection",
+]);
+
+const repaymentApproaches = new Set([
+ "autopay",
+ "extra_income",
+ "negotiate",
+ "refinance",
+ "snowball",
+ "avalanche",
+ "family_plan",
+ "other",
+]);
+const MIN_AGGREGATE_SAMPLE = 30;
+const MIN_PROFILE_GROUP = 5;
+
+type StoryRow = {
+ id: string;
+ vault_id: string;
+ debt_id: string;
+ anonymous_name: string;
+ country_code: string;
+ debt_kind: string;
+ amount_band: string;
+ currency: string;
+ repayment_approach: string;
+ story_text: string;
+ status: string;
+ created_at: string;
+ encouragement_count: number;
+};
+
+type SharedWalkerRow = {
+ id: string;
+ country_code: string;
+ debt_count: number;
+ original_total: number;
+ balance_total: number;
+};
+
+function stableWalkerCode(id: string) {
+ let hash = 2_166_136_261;
+ for (const character of id) {
+ hash ^= character.charCodeAt(0);
+ hash = Math.imul(hash, 16_777_619);
+ }
+ return (hash >>> 0).toString(36).toUpperCase().padStart(7, "0").slice(0, 7);
+}
+
+function repaymentStage(original: number, balance: number, debtCount: number) {
+ if (debtCount < 1 || original <= 0) return "setting_up";
+ const progress = Math.max(0, Math.min(1, 1 - (balance / original)));
+ if (progress >= 0.8) return "near_shore";
+ if (progress >= 0.4) return "moving";
+ if (progress > 0) return "started";
+ return "mapped";
+}
+
+function publicStory(row: StoryRow, encouraged = false) {
+ return {
+ id: row.id,
+ anonymousName: row.anonymous_name,
+ countryCode: row.country_code,
+ debtKind: row.debt_kind,
+ amountBand: row.amount_band,
+ currency: row.currency,
+ repaymentApproach: row.repayment_approach,
+ storyText: row.story_text,
+ status: row.status,
+ createdAt: row.created_at,
+ encouragementCount: Number(row.encouragement_count ?? 0),
+ encouraged,
+ };
+}
+
+function redactStory(source: string) {
+ const replacements = [
+ /\b[A-Z0-9._%+-]+@[A-Z0-9.-]+\.[A-Z]{2,}\b/gi,
+ /(?:https?:\/\/|www\.)\S+/gi,
+ /(?:微信|vx|wechat|whatsapp|telegram|line|qq|邮箱|电话|手机号|手机)\s*[::]?\s*\S+/gi,
+ /\+?\d[\d\s()-]{6,}\d/g,
+ /\b\d{4,}\b/g,
+ ];
+ let text = source;
+ let redacted = false;
+ for (const pattern of replacements) {
+ text = text.replace(pattern, () => {
+ redacted = true;
+ return "[private detail hidden]";
+ });
+ }
+ return { text: text.replace(/\s{3,}/g, " ").trim(), redacted };
+}
+
+function amountBand(value: number) {
+ if (!Number.isFinite(value) || value <= 0) return "0";
+ const boundaries = [0, 1_000, 5_000, 10_000, 25_000, 50_000, 100_000, 250_000, 500_000, 1_000_000, 2_500_000, 5_000_000, 10_000_000, 25_000_000, 50_000_000, 100_000_000];
+ for (let index = 1; index < boundaries.length; index += 1) {
+ if (value <= boundaries[index]) {
+ return `${boundaries[index - 1].toLocaleString("en-US")}–${boundaries[index].toLocaleString("en-US")}`;
+ }
+ }
+ return `${boundaries.at(-1)!.toLocaleString("en-US")}+`;
+}
+
+async function optionalVault(request: Request) {
+ try {
+ return await requireVault(request);
+ } catch (error) {
+ if (error instanceof HttpError && error.status === 401) return null;
+ throw error;
+ }
+}
+
+export async function GET(request: Request) {
+ try {
+ const db = getD1();
+ const vault = await optionalVault(request);
+ const [pulseRow, districtRows, sharedWalkerRows, walkerDebtKindRows] = await Promise.all([
+ db.prepare(
+ `SELECT
+ (SELECT COUNT(*) FROM vaults) AS population,
+ (SELECT COUNT(*) FROM debts) AS recorded_debts,
+ (SELECT COUNT(*) FROM payment_records) AS confirmed_payments,
+ (SELECT COUNT(DISTINCT country_code) FROM vaults WHERE country_code <> '') AS countries`,
+ ).first<{ population: number; recorded_debts: number; confirmed_payments: number; countries: number }>(),
+ db.prepare(
+ `SELECT kind AS key, COUNT(*) AS count
+ FROM debts GROUP BY kind ORDER BY count DESC, key ASC`,
+ ).all<{ key: string; count: number }>(),
+ db.prepare(
+ `SELECT
+ v.id,
+ v.country_code,
+ COUNT(d.id) AS debt_count,
+ COALESCE(SUM(d.original), 0) AS original_total,
+ COALESCE(SUM(d.balance), 0) AS balance_total
+ FROM vaults v
+ LEFT JOIN debts d ON d.vault_id = v.id
+ GROUP BY v.id, v.country_code, v.created_at
+ ORDER BY v.created_at DESC
+ LIMIT 80`,
+ ).all(),
+ db.prepare(
+ `SELECT vault_id, kind, balance
+ FROM debts
+ ORDER BY balance DESC, created_at ASC`,
+ ).all<{ vault_id: string; kind: string; balance: number }>(),
+ ]);
+ const primaryDebtKinds = new Map();
+ for (const debt of walkerDebtKindRows.results) {
+ if (!primaryDebtKinds.has(debt.vault_id)) primaryDebtKinds.set(debt.vault_id, debt.kind);
+ }
+ const published = await db.prepare(
+ `SELECT s.*,
+ (SELECT COUNT(*) FROM story_encouragements e WHERE e.story_id = s.id) AS encouragement_count
+ FROM public_stories s
+ WHERE s.status = 'published'
+ ORDER BY s.created_at DESC
+ LIMIT 60`,
+ ).all();
+ const countRow = await db.prepare(
+ "SELECT COUNT(*) AS count FROM public_stories WHERE status = 'published'",
+ ).first<{ count: number }>();
+ const sampleSize = Number(countRow?.count ?? 0);
+ const profileRows = await db.prepare(
+ `SELECT v.id AS vault_id, v.mbti, d.currency, d.balance
+ FROM vaults v JOIN debts d ON d.vault_id = v.id
+ WHERE v.discovery_consent = 1 AND v.mbti <> ''`,
+ ).all<{ vault_id: string; mbti: string; currency: string; balance: number }>();
+ const profileVaults = new Set(profileRows.results.map((row) => row.vault_id));
+ const mbtiGroups = new Map; totalUsd: number }>();
+ for (const row of profileRows.results) {
+ const group = mbtiGroups.get(row.mbti) ?? { vaults: new Set(), totalUsd: 0 };
+ group.vaults.add(row.vault_id);
+ group.totalUsd += convertCurrency(Number(row.balance), row.currency, "USD", fallbackUsdRates);
+ mbtiGroups.set(row.mbti, group);
+ }
+ const profileReady = profileVaults.size >= MIN_AGGREGATE_SAMPLE;
+ const mbtiDebt = profileReady ? [...mbtiGroups.entries()]
+ .filter(([, group]) => group.vaults.size >= MIN_PROFILE_GROUP)
+ .map(([key, group]) => ({ key, count: group.vaults.size, averageUsd: Math.round((group.totalUsd / group.vaults.size) / 100) * 100 }))
+ .sort((left, right) => right.averageUsd - left.averageUsd) : [];
+ let insights: {
+ ready: boolean;
+ sampleSize: number;
+ minSample: number;
+ debtKinds: Array<{ key: string; count: number }>;
+ repaymentApproaches: Array<{ key: string; count: number }>;
+ profileReady: boolean;
+ profileSampleSize: number;
+ profileMinSample: number;
+ mbtiDebt: Array<{ key: string; count: number; averageUsd: number }>;
+ } = { ready: false, sampleSize, minSample: MIN_AGGREGATE_SAMPLE, debtKinds: [], repaymentApproaches: [], profileReady, profileSampleSize: profileVaults.size, profileMinSample: MIN_AGGREGATE_SAMPLE, mbtiDebt };
+ if (sampleSize >= MIN_AGGREGATE_SAMPLE) {
+ const [kindRows, approachRows] = await Promise.all([
+ db.prepare(
+ "SELECT debt_kind AS key, COUNT(*) AS count FROM public_stories WHERE status = 'published' GROUP BY debt_kind ORDER BY count DESC",
+ ).all<{ key: string; count: number }>(),
+ db.prepare(
+ "SELECT repayment_approach AS key, COUNT(*) AS count FROM public_stories WHERE status = 'published' GROUP BY repayment_approach ORDER BY count DESC",
+ ).all<{ key: string; count: number }>(),
+ ]);
+ insights = {
+ ready: true,
+ sampleSize,
+ minSample: MIN_AGGREGATE_SAMPLE,
+ debtKinds: kindRows.results.map((row) => ({ key: row.key, count: Number(row.count) })),
+ repaymentApproaches: approachRows.results.map((row) => ({ key: row.key, count: Number(row.count) })),
+ profileReady,
+ profileSampleSize: profileVaults.size,
+ profileMinSample: MIN_AGGREGATE_SAMPLE,
+ mbtiDebt,
+ };
+ }
+
+ let encouraged = new Set();
+ let mine: StoryRow[] = [];
+ let policyAccepted = false;
+ if (vault) {
+ const [encouragementRows, mineResult, acceptanceRows] = await Promise.all([
+ db.prepare(
+ "SELECT story_id FROM story_encouragements WHERE vault_id = ?1",
+ ).bind(vault.id).all<{ story_id: string }>(),
+ db.prepare(
+ `SELECT s.*,
+ (SELECT COUNT(*) FROM story_encouragements e WHERE e.story_id = s.id) AS encouragement_count
+ FROM public_stories s
+ WHERE s.vault_id = ?1
+ ORDER BY s.created_at DESC
+ LIMIT 20`,
+ ).bind(vault.id).all(),
+ db.prepare(
+ "SELECT policy_key FROM policy_acceptances WHERE vault_id = ?1 AND policy_version = ?2",
+ ).bind(vault.id, SAFETY_POLICY_VERSION).all<{ policy_key: string }>(),
+ ]);
+ encouraged = new Set(encouragementRows.results.map((row) => row.story_id));
+ mine = mineResult.results;
+ const acceptedKeys = new Set(acceptanceRows.results.map((row) => row.policy_key));
+ policyAccepted = acceptedKeys.has(COMMUNITY_POLICY_KEY) && acceptedKeys.has(COMMUNITY_AGE_KEY);
+ }
+
+ return noStoreJson({
+ worldPulse: {
+ population: Number(pulseRow?.population ?? 0),
+ recordedDebts: Number(pulseRow?.recorded_debts ?? 0),
+ confirmedPayments: Number(pulseRow?.confirmed_payments ?? 0),
+ countries: Number(pulseRow?.countries ?? 0),
+ districts: districtRows.results.map((row) => ({
+ key: row.key,
+ count: Number(row.count) >= 3 ? Number(row.count) : null,
+ tier: Math.min(5, Math.max(1, Math.ceil(Number(row.count) / 10))),
+ })),
+ },
+ sharedWalkers: sharedWalkerRows.results.map((walker) => ({
+ id: `walker-${stableWalkerCode(walker.id)}`,
+ anonymousName: `Walker-${stableWalkerCode(walker.id).slice(0, 5)}`,
+ countryCode: walker.country_code,
+ debtCountBand: Number(walker.debt_count ?? 0) < 1
+ ? "none"
+ : Number(walker.debt_count ?? 0) === 1
+ ? "single"
+ : "multiple",
+ primaryDebtKind: primaryDebtKinds.get(walker.id) ?? "other",
+ repaymentStage: repaymentStage(
+ Number(walker.original_total ?? 0),
+ Number(walker.balance_total ?? 0),
+ Number(walker.debt_count ?? 0),
+ ),
+ isMine: vault?.id === walker.id,
+ })),
+ stories: published.results.map((story) => publicStory(story, encouraged.has(story.id))),
+ mine: mine.map((story) => publicStory(story)),
+ insights,
+ policy: { version: SAFETY_POLICY_VERSION, accepted: policyAccepted },
+ });
+ } catch (error) {
+ return routeError(error);
+ }
+}
+
+export async function POST(request: Request) {
+ try {
+ assertSameOrigin(request);
+ const vault = await requireVault(request);
+ const payload = await request.json() as {
+ action?: "publish" | "encourage" | "report" | "delete_story";
+ debtId?: string;
+ storyId?: string;
+ storyText?: string;
+ repaymentApproach?: string;
+ reason?: string;
+ details?: string;
+ rulesAccepted?: boolean;
+ ageConfirmed?: boolean;
+ };
+ const db = getD1();
+
+ if (payload.action === "publish") {
+ const debtId = cleanText(payload.debtId, 80);
+ const source = cleanText(payload.storyText, 600);
+ const repaymentApproach = repaymentApproaches.has(payload.repaymentApproach ?? "")
+ ? payload.repaymentApproach!
+ : "other";
+ if (source.length < 20) throw new HttpError(400, "The anonymous story is too short.");
+ const debt = await db.prepare(
+ "SELECT id, vault_id, kind, currency, balance, sharing_mode FROM debts WHERE id = ?1 AND vault_id = ?2 LIMIT 1",
+ ).bind(debtId, vault.id).first<{ id: string; vault_id: string; kind: string; currency: string; balance: number; sharing_mode: string }>();
+ if (!debt) throw new HttpError(404, "Debt not found.");
+ if (debt.sharing_mode !== "range") throw new HttpError(403, "This debt is private. Choose anonymous range sharing first.");
+ const existing = await db.prepare(
+ "SELECT id FROM public_stories WHERE debt_id = ?1 AND status IN ('pending', 'published', 'review') LIMIT 1",
+ ).bind(debt.id).first();
+ if (existing) throw new HttpError(409, "This debt already has a story awaiting or through review.");
+ const redaction = redactStory(source);
+ if (redaction.text.replace(/\[private detail hidden\]/g, "").trim().length < 12) {
+ throw new HttpError(400, "The story contains too little shareable text after privacy filtering.");
+ }
+ const acceptanceRows = await db.prepare(
+ "SELECT policy_key FROM policy_acceptances WHERE vault_id = ?1 AND policy_version = ?2",
+ ).bind(vault.id, SAFETY_POLICY_VERSION).all<{ policy_key: string }>();
+ const acceptedKeys = new Set(acceptanceRows.results.map((row) => row.policy_key));
+ const hasCurrentPolicy = acceptedKeys.has(COMMUNITY_POLICY_KEY) && acceptedKeys.has(COMMUNITY_AGE_KEY);
+ if (!hasCurrentPolicy && (!payload.rulesAccepted || !payload.ageConfirmed)) {
+ throw new HttpError(428, "Confirm the current community rules, privacy notice, and age requirement before publishing.");
+ }
+ if (!hasCurrentPolicy) {
+ await db.batch([
+ db.prepare(
+ `INSERT OR IGNORE INTO policy_acceptances (id, vault_id, policy_key, policy_version)
+ VALUES (?1, ?2, ?3, ?4)`,
+ ).bind(crypto.randomUUID(), vault.id, COMMUNITY_POLICY_KEY, SAFETY_POLICY_VERSION),
+ db.prepare(
+ `INSERT OR IGNORE INTO policy_acceptances (id, vault_id, policy_key, policy_version)
+ VALUES (?1, ?2, ?3, ?4)`,
+ ).bind(crypto.randomUUID(), vault.id, COMMUNITY_AGE_KEY, SAFETY_POLICY_VERSION),
+ ]);
+ }
+ await consumeCommunityRateLimit(vault.id, "publish");
+ const id = crypto.randomUUID();
+ const suffix = id.replace(/-/g, "").slice(0, 4).toUpperCase();
+ await db.prepare(
+ `INSERT INTO public_stories
+ (id, vault_id, debt_id, anonymous_name, country_code, debt_kind, amount_band, currency, repayment_approach, story_text, status)
+ VALUES (?1, ?2, ?3, ?4, ?5, ?6, ?7, ?8, ?9, ?10, 'pending')`,
+ ).bind(id, vault.id, debt.id, `Walker-${suffix}`, vault.country_code, debt.kind, amountBand(debt.balance), debt.currency, repaymentApproach, redaction.text).run();
+ return noStoreJson({ status: "pending", redacted: redaction.redacted }, { status: 201 });
+ }
+
+ if (payload.action === "delete_story") {
+ const storyId = cleanText(payload.storyId, 80);
+ const deleted = await db.prepare(
+ "DELETE FROM public_stories WHERE id = ?1 AND vault_id = ?2",
+ ).bind(storyId, vault.id).run();
+ if (Number(deleted.meta?.changes ?? 0) < 1) throw new HttpError(404, "Story not found.");
+ return noStoreJson({ deleted: true, storyId });
+ }
+
+ const storyId = cleanText(payload.storyId, 80);
+ const story = await db.prepare(
+ "SELECT id, vault_id, status FROM public_stories WHERE id = ?1 LIMIT 1",
+ ).bind(storyId).first<{ id: string; vault_id: string; status: string }>();
+ if (!story || story.status !== "published") throw new HttpError(404, "Published story not found.");
+ if (story.vault_id === vault.id) throw new HttpError(400, "You cannot act on your own story.");
+
+ if (payload.action === "encourage") {
+ const existing = await db.prepare(
+ "SELECT id FROM story_encouragements WHERE story_id = ?1 AND vault_id = ?2 LIMIT 1",
+ ).bind(story.id, vault.id).first();
+ if (existing) {
+ const count = await db.prepare(
+ "SELECT COUNT(*) AS count FROM story_encouragements WHERE story_id = ?1",
+ ).bind(story.id).first<{ count: number }>();
+ return noStoreJson({ encouraged: true, count: Number(count?.count ?? 0) });
+ }
+ await consumeCommunityRateLimit(vault.id, "encourage");
+ await db.prepare(
+ "INSERT OR IGNORE INTO story_encouragements (id, story_id, vault_id) VALUES (?1, ?2, ?3)",
+ ).bind(crypto.randomUUID(), story.id, vault.id).run();
+ const count = await db.prepare(
+ "SELECT COUNT(*) AS count FROM story_encouragements WHERE story_id = ?1",
+ ).bind(story.id).first<{ count: number }>();
+ return noStoreJson({ encouraged: true, count: Number(count?.count ?? 0) });
+ }
+
+ if (payload.action === "report") {
+ const existing = await db.prepare(
+ "SELECT id FROM story_reports WHERE story_id = ?1 AND reporter_vault_id = ?2 LIMIT 1",
+ ).bind(story.id, vault.id).first();
+ if (existing) return noStoreJson({ reported: true });
+ await consumeCommunityRateLimit(vault.id, "report");
+ const reason = reportReasons.has(payload.reason ?? "") ? payload.reason! : "bad_advice";
+ const details = redactStory(cleanText(payload.details, 240)).text;
+ await db.prepare(
+ `INSERT OR IGNORE INTO story_reports
+ (id, story_id, reporter_vault_id, reason, details, status)
+ VALUES (?1, ?2, ?3, ?4, ?5, 'open')`,
+ ).bind(crypto.randomUUID(), story.id, vault.id, reason, details).run();
+ if (["scam", "identity_exposure", "self_harm", "debt_collection"].includes(reason)) {
+ await db.prepare(
+ "UPDATE public_stories SET status = 'review', updated_at = CURRENT_TIMESTAMP WHERE id = ?1 AND status = 'published'",
+ ).bind(story.id).run();
+ }
+ return noStoreJson({ reported: true });
+ }
+
+ throw new HttpError(400, "Unknown community action.");
+ } catch (error) {
+ return routeError(error);
+ }
+}
diff --git a/app/api/debts/route.ts b/app/api/debts/route.ts
new file mode 100644
index 0000000..541389f
--- /dev/null
+++ b/app/api/debts/route.ts
@@ -0,0 +1,150 @@
+import { getD1 } from "@/db";
+import {
+ HttpError,
+ assertSameOrigin,
+ noStoreJson,
+ requireVault,
+ routeError,
+ validateDebt,
+} from "@/lib/vault-server";
+import { qualifyReferral } from "@/lib/referral-server";
+
+export const dynamic = "force-dynamic";
+
+export async function POST(request: Request) {
+ try {
+ assertSameOrigin(request);
+ const vault = await requireVault(request);
+ const debt = { ...validateDebt(await request.json()), id: crypto.randomUUID() };
+ await getD1()
+ .prepare(
+ `INSERT INTO debts
+ (id, vault_id, kind, custom_label, currency, original, balance, monthly, apr, minimum_payment, payment_status, remaining_months, due_day, method, sharing_mode, last_paid_at, payments)
+ VALUES (?1, ?2, ?3, ?4, ?5, ?6, ?7, ?8, ?9, ?10, ?11, ?12, ?13, ?14, ?15, ?16, ?17)`,
+ )
+ .bind(
+ debt.id,
+ vault.id,
+ debt.kind,
+ debt.customLabel,
+ debt.currency,
+ debt.original,
+ debt.balance,
+ debt.monthly,
+ debt.apr,
+ debt.minimumPayment,
+ debt.paymentStatus,
+ debt.remainingMonths,
+ debt.dueDay,
+ debt.method,
+ debt.sharingMode,
+ debt.lastPaidAt,
+ debt.payments,
+ )
+ .run();
+ const referralActivated = await qualifyReferral(vault.id);
+ return noStoreJson({ debt: { ...debt, history: [] }, referralActivated }, { status: 201 });
+ } catch (error) {
+ return routeError(error);
+ }
+}
+
+export async function PATCH(request: Request) {
+ try {
+ assertSameOrigin(request);
+ const vault = await requireVault(request);
+ const payload = (await request.json()) as { id?: string } & Record;
+ if (!payload.id) throw new HttpError(400, "Debt id is required.");
+ const owned = await getD1()
+ .prepare("SELECT * FROM debts WHERE id = ?1 AND vault_id = ?2 LIMIT 1")
+ .bind(payload.id, vault.id)
+ .first<{
+ id: string;
+ kind: string;
+ custom_label: string | null;
+ currency: string;
+ original: number;
+ balance: number;
+ monthly: number;
+ apr: number | null;
+ minimum_payment: number | null;
+ payment_status: string;
+ remaining_months: number | null;
+ due_day: number;
+ method: string;
+ sharing_mode: string;
+ last_paid_at: string | null;
+ payments: number;
+ }>();
+ if (!owned) throw new HttpError(404, "Debt not found.");
+ const debt = validateDebt({
+ id: owned.id,
+ kind: typeof payload.kind === "string" ? payload.kind : owned.kind,
+ customLabel: typeof payload.customLabel === "string" ? payload.customLabel : owned.custom_label ?? undefined,
+ currency: typeof payload.currency === "string" ? payload.currency : owned.currency,
+ original: payload.original === undefined ? owned.original : Number(payload.original),
+ balance: payload.balance === undefined ? owned.balance : Number(payload.balance),
+ monthly: payload.monthly === undefined ? owned.monthly : Number(payload.monthly),
+ apr: payload.apr === undefined ? owned.apr : payload.apr === null || payload.apr === "" ? null : Number(payload.apr),
+ minimumPayment: payload.minimumPayment === undefined ? owned.minimum_payment : payload.minimumPayment === null || payload.minimumPayment === "" ? null : Number(payload.minimumPayment),
+ paymentStatus: typeof payload.paymentStatus === "string" ? payload.paymentStatus : owned.payment_status,
+ remainingMonths: payload.remainingMonths === undefined ? owned.remaining_months : payload.remainingMonths === null || payload.remainingMonths === "" ? null : Number(payload.remainingMonths),
+ dueDay: payload.dueDay === undefined ? owned.due_day : Number(payload.dueDay),
+ method: typeof payload.method === "string" ? payload.method : owned.method,
+ sharingMode: typeof payload.sharingMode === "string" ? payload.sharingMode : owned.sharing_mode,
+ lastPaidAt: owned.last_paid_at ?? undefined,
+ payments: owned.payments,
+ });
+ await getD1()
+ .prepare(
+ `UPDATE debts
+ SET kind = ?1, custom_label = ?2, currency = ?3, original = ?4, balance = ?5, monthly = ?6,
+ apr = ?7, minimum_payment = ?8, payment_status = ?9, remaining_months = ?10,
+ due_day = ?11, method = ?12, sharing_mode = ?13, updated_at = CURRENT_TIMESTAMP
+ WHERE id = ?14 AND vault_id = ?15`,
+ )
+ .bind(
+ debt.kind,
+ debt.customLabel,
+ debt.currency,
+ debt.original,
+ debt.balance,
+ debt.monthly,
+ debt.apr,
+ debt.minimumPayment,
+ debt.paymentStatus,
+ debt.remainingMonths,
+ debt.dueDay,
+ debt.method,
+ debt.sharingMode,
+ debt.id,
+ vault.id,
+ )
+ .run();
+ return noStoreJson({ debt });
+ } catch (error) {
+ return routeError(error);
+ }
+}
+
+export async function DELETE(request: Request) {
+ try {
+ assertSameOrigin(request);
+ const vault = await requireVault(request);
+ const id = new URL(request.url).searchParams.get("id");
+ if (!id) throw new HttpError(400, "Debt id is required.");
+ const db = getD1();
+ const owned = await db
+ .prepare("SELECT id FROM debts WHERE id = ?1 AND vault_id = ?2 LIMIT 1")
+ .bind(id, vault.id)
+ .first();
+ if (!owned) throw new HttpError(404, "Debt not found.");
+ await db.batch([
+ db.prepare("DELETE FROM payment_records WHERE debt_id = ?1 AND vault_id = ?2").bind(id, vault.id),
+ db.prepare("DELETE FROM debts WHERE id = ?1 AND vault_id = ?2").bind(id, vault.id),
+ ]);
+ return noStoreJson({ deleted: true });
+ } catch (error) {
+ return routeError(error);
+ }
+}
diff --git a/app/api/payments/route.ts b/app/api/payments/route.ts
new file mode 100644
index 0000000..59f7b2c
--- /dev/null
+++ b/app/api/payments/route.ts
@@ -0,0 +1,124 @@
+import { getD1 } from "@/db";
+import {
+ HttpError,
+ assertSameOrigin,
+ cleanNumber,
+ cleanText,
+ noStoreJson,
+ requireVault,
+ routeError,
+} from "@/lib/vault-server";
+
+export const dynamic = "force-dynamic";
+
+const sources = new Set(["self_report", "prepayment", "lucky_income"]);
+const incomeTypes = new Set(["bonus", "freelance", "refund", "gift", "sale", "other"]);
+
+function localEventDate(offsetValue: unknown) {
+ const offset = Math.round(cleanNumber(offsetValue, -840, 840, 0));
+ return new Date(Date.now() - offset * 60_000).toISOString().slice(0, 10);
+}
+
+export async function GET(request: Request) {
+ try {
+ const vault = await requireVault(request);
+ const url = new URL(request.url);
+ const eventDate = localEventDate(url.searchParams.get("timezoneOffset"));
+ const claim = await getD1().prepare(
+ "SELECT id FROM lucky_income_claims WHERE vault_id = ?1 AND event_date = ?2 LIMIT 1",
+ ).bind(vault.id, eventDate).first();
+ return noStoreJson({ eventDate, luckyIncomeUsed: Boolean(claim) });
+ } catch (error) {
+ return routeError(error);
+ }
+}
+
+export async function POST(request: Request) {
+ try {
+ assertSameOrigin(request);
+ const vault = await requireVault(request);
+ const payload = (await request.json()) as {
+ debtId?: string;
+ cashPayment?: number;
+ newBalance?: number;
+ scheduledDate?: string;
+ source?: string;
+ incomeType?: string;
+ timezoneOffset?: number;
+ };
+ const debtId = cleanText(payload.debtId, 80);
+ if (!debtId) throw new HttpError(400, "Debt id is required.");
+ const source = sources.has(payload.source ?? "") ? payload.source! : "self_report";
+ const incomeType = source === "lucky_income" && incomeTypes.has(payload.incomeType ?? "")
+ ? payload.incomeType!
+ : null;
+ if (source === "lucky_income" && !incomeType) throw new HttpError(400, "A real income type is required.");
+
+ const db = getD1();
+ const debt = await db.prepare(
+ "SELECT id, balance, payments FROM debts WHERE id = ?1 AND vault_id = ?2 LIMIT 1",
+ ).bind(debtId, vault.id).first<{ id: string; balance: number; payments: number }>();
+ if (!debt) throw new HttpError(404, "Debt not found.");
+
+ const cashPayment = cleanNumber(payload.cashPayment, 0, 1_000_000_000_000);
+ if (cashPayment <= 0) throw new HttpError(400, "The real cash payment must be greater than zero.");
+ const newBalance = cleanNumber(payload.newBalance, 0, debt.balance);
+ const confirmedAt = new Date().toISOString();
+ const eventDate = localEventDate(payload.timezoneOffset);
+ const scheduledDate = source === "self_report" && typeof payload.scheduledDate === "string"
+ ? payload.scheduledDate.slice(0, 10)
+ : null;
+ const paymentId = crypto.randomUUID();
+ const shoreValueId = crypto.randomUUID();
+
+ if (source === "lucky_income") {
+ const used = await db.prepare(
+ "SELECT id FROM lucky_income_claims WHERE vault_id = ?1 AND event_date = ?2 LIMIT 1",
+ ).bind(vault.id, eventDate).first();
+ if (used) throw new HttpError(409, "Today's lucky-income record has already been used.");
+ }
+
+ const statements = [];
+ if (source === "lucky_income") {
+ statements.push(db.prepare(
+ "INSERT INTO lucky_income_claims (id, vault_id, event_date) VALUES (?1, ?2, ?3)",
+ ).bind(crypto.randomUUID(), vault.id, eventDate));
+ }
+ statements.push(
+ db.prepare(
+ `INSERT INTO payment_records
+ (id, vault_id, debt_id, scheduled_date, confirmed_at, event_date, cash_payment, new_balance, source, income_type)
+ VALUES (?1, ?2, ?3, ?4, ?5, ?6, ?7, ?8, ?9, ?10)`,
+ ).bind(paymentId, vault.id, debt.id, scheduledDate, confirmedAt, eventDate, cashPayment, newBalance, source, incomeType),
+ db.prepare(
+ `UPDATE debts
+ SET balance = ?1, last_paid_at = CASE WHEN ?2 = 'self_report' THEN ?3 ELSE last_paid_at END,
+ payments = payments + 1, updated_at = CURRENT_TIMESTAMP
+ WHERE id = ?4 AND vault_id = ?5`,
+ ).bind(newBalance, source, confirmedAt, debt.id, vault.id),
+ db.prepare(
+ `INSERT INTO shore_value_ledger
+ (id, vault_id, event_key, event_type, points, reference_id)
+ VALUES (?1, ?2, ?3, 'verified_payment', 5, ?4)`,
+ ).bind(shoreValueId, vault.id, `payment:${paymentId}`, paymentId),
+ db.prepare(
+ `INSERT INTO starlight_wallets
+ (vault_id, available, lifetime_earned, lifetime_sent, lifetime_received, updated_at)
+ VALUES (?1, 1, 1, 0, 0, CURRENT_TIMESTAMP)
+ ON CONFLICT(vault_id) DO UPDATE SET
+ available = available + 1,
+ lifetime_earned = lifetime_earned + 1,
+ updated_at = CURRENT_TIMESTAMP`,
+ ).bind(vault.id),
+ );
+ await db.batch(statements);
+
+ return noStoreJson({
+ payment: { id: paymentId, confirmedAt, eventDate, cashPayment, newBalance, source, incomeType },
+ debt: { id: debt.id, balance: newBalance, lastPaidAt: source === "self_report" ? confirmedAt : undefined, payments: debt.payments + 1 },
+ rewards: { shoreValue: 5, starlight: 1 },
+ }, { status: 201 });
+ } catch (error) {
+ return routeError(error);
+ }
+}
diff --git a/app/api/progress/route.ts b/app/api/progress/route.ts
new file mode 100644
index 0000000..8a58b5d
--- /dev/null
+++ b/app/api/progress/route.ts
@@ -0,0 +1,13 @@
+import { getShoreProgress } from "@/lib/shore-value-server";
+import { noStoreJson, requireVault, routeError } from "@/lib/vault-server";
+
+export const dynamic = "force-dynamic";
+
+export async function GET(request: Request) {
+ try {
+ const vault = await requireVault(request);
+ return noStoreJson({ progress: await getShoreProgress(vault.id) });
+ } catch (error) {
+ return routeError(error);
+ }
+}
diff --git a/app/api/rates/route.ts b/app/api/rates/route.ts
new file mode 100644
index 0000000..47af7d3
--- /dev/null
+++ b/app/api/rates/route.ts
@@ -0,0 +1,37 @@
+import { fallbackUsdRates } from "@/lib/exchange-rates";
+
+export const dynamic = "force-dynamic";
+
+type RateRow = {
+ date: string;
+ base: string;
+ quote: string;
+ rate: number;
+};
+
+export async function GET() {
+ try {
+ const response = await fetch("https://api.frankfurter.dev/v2/rates?base=USD", {
+ headers: { Accept: "application/json" },
+ });
+ if (!response.ok) throw new Error("Rate provider unavailable");
+ const rows = await response.json() as RateRow[];
+ const rates: Record = { ...fallbackUsdRates, USD: 1 };
+ let date = "";
+ for (const row of rows) {
+ if (row.base === "USD" && Number.isFinite(row.rate) && row.rate > 0) {
+ rates[row.quote] = row.rate;
+ if (row.date > date) date = row.date;
+ }
+ }
+ return Response.json(
+ { base: "USD", date, rates, source: "Frankfurter", fallback: false },
+ { headers: { "Cache-Control": "public, max-age=3600, s-maxage=21600, stale-while-revalidate=86400" } },
+ );
+ } catch {
+ return Response.json(
+ { base: "USD", date: null, rates: fallbackUsdRates, source: "fallback", fallback: true },
+ { headers: { "Cache-Control": "public, max-age=300" } },
+ );
+ }
+}
diff --git a/app/api/referral/route.ts b/app/api/referral/route.ts
new file mode 100644
index 0000000..54734be
--- /dev/null
+++ b/app/api/referral/route.ts
@@ -0,0 +1,13 @@
+import { getReferralState } from "@/lib/referral-server";
+import { noStoreJson, requireVault, routeError } from "@/lib/vault-server";
+
+export const dynamic = "force-dynamic";
+
+export async function GET(request: Request) {
+ try {
+ const vault = await requireVault(request);
+ return noStoreJson({ referral: await getReferralState(vault.id) });
+ } catch (error) {
+ return routeError(error);
+ }
+}
diff --git a/app/api/security/route.ts b/app/api/security/route.ts
new file mode 100644
index 0000000..ca9fd0a
--- /dev/null
+++ b/app/api/security/route.ts
@@ -0,0 +1,8 @@
+import { noStoreJson } from "@/lib/vault-server";
+import { turnstilePublicState } from "@/lib/turnstile-server";
+
+export const dynamic = "force-dynamic";
+
+export async function GET() {
+ return noStoreJson({ turnstile: turnstilePublicState() });
+}
diff --git a/app/api/vault/route.ts b/app/api/vault/route.ts
new file mode 100644
index 0000000..8c3684d
--- /dev/null
+++ b/app/api/vault/route.ts
@@ -0,0 +1,331 @@
+import { getD1 } from "@/db";
+import { accountHasVault, clearAccountSession, requireAccount } from "@/lib/account-server";
+import { consumeBetaInvite } from "@/lib/beta-server";
+import {
+ HttpError,
+ assertSameOrigin,
+ cleanNumber,
+ cleanText,
+ clearSessionCookie,
+ generateRecoveryCode,
+ hashRecoveryCode,
+ ensureVaultStorageSchema,
+ loadVaultState,
+ noStoreJson,
+ normalizeRecoveryCode,
+ requireVault,
+ routeError,
+ validateDebt,
+ withSessionCookie,
+} from "@/lib/vault-server";
+
+export const dynamic = "force-dynamic";
+
+const ageBands = new Set(["18-24", "25-34", "35-44", "45-54", "55-64", "65+"]);
+const genders = new Set(["woman", "man", "nonbinary", "self_described", "prefer_not_say"]);
+const mbtiTypes = new Set(["INTJ", "INTP", "ENTJ", "ENTP", "INFJ", "INFP", "ENFJ", "ENFP", "ISTJ", "ISFJ", "ESTJ", "ESFJ", "ISTP", "ISFP", "ESTP", "ESFP"]);
+const zodiacSigns = new Set(["aries", "taurus", "gemini", "cancer", "leo", "virgo", "libra", "scorpio", "sagittarius", "capricorn", "aquarius", "pisces"]);
+const repaymentOutlooks = new Set(["clear_plan", "trying", "uncertain", "no_current_way"]);
+
+type ProfileInput = {
+ alias?: string; region?: string; pressure?: string; ageBand?: string; gender?: string; mbti?: string; zodiac?: string;
+ selfDescription?: string; repaymentPlan?: string; repaymentOutlook?: string; incomePlan?: string;
+ countryCode?: string; countryName?: string; displayCurrency?: string; monthlyIncome?: number; monthlyExpenses?: number;
+};
+
+export async function GET(request: Request) {
+ try {
+ await ensureVaultStorageSchema();
+ const vault = await requireVault(request);
+ const state = await loadVaultState(vault);
+ if (new URL(request.url).searchParams.get("download") === "1") {
+ return new Response(JSON.stringify({ exportedAt: new Date().toISOString(), ...state }, null, 2), {
+ headers: {
+ "Cache-Control": "no-store, private",
+ "Content-Disposition": 'attachment; filename="debt-world-export.json"',
+ "Content-Type": "application/json; charset=utf-8",
+ },
+ });
+ }
+ return noStoreJson({ vault: state });
+ } catch (error) {
+ return routeError(error);
+ }
+}
+
+export async function POST(request: Request) {
+ let stage = "request";
+ try {
+ assertSameOrigin(request);
+ stage = "payload";
+ const payload = (await request.json()) as {
+ action?: "create" | "recover" | "rotate";
+ recoveryCode?: string;
+ profile?: ProfileInput;
+ position?: { x?: number; y?: number };
+ locale?: string;
+ discoveryConsent?: boolean;
+ inviteCode?: string;
+ betaConsent?: boolean;
+ debts?: unknown[];
+ };
+ stage = "account";
+ const account = await requireAccount(request);
+ stage = "storage_schema";
+ await ensureVaultStorageSchema();
+
+ if (payload.action === "recover") {
+ stage = "recover";
+ if (await accountHasVault(account.id)) {
+ throw new HttpError(409, "This account already has a linked world.");
+ }
+ const code = normalizeRecoveryCode(payload.recoveryCode);
+ if (code.length !== 26 || !code.startsWith("DW")) {
+ throw new HttpError(400, "The recovery code format is invalid.");
+ }
+ const recoveryHash = await hashRecoveryCode(code);
+ const vault = await getD1()
+ .prepare(
+ `SELECT v.* FROM vaults v
+ LEFT JOIN account_vaults av ON av.vault_id = v.id
+ WHERE v.recovery_hash = ?1 AND av.vault_id IS NULL LIMIT 1`,
+ )
+ .bind(recoveryHash)
+ .first();
+ if (!vault) throw new HttpError(404, "No vault matched that recovery code.");
+ await getD1().prepare(
+ "INSERT INTO account_vaults (account_id, vault_id) VALUES (?1, ?2)",
+ ).bind(account.id, vault.id).run();
+ const response = noStoreJson({ vault: await loadVaultState(vault) });
+ return withSessionCookie(response, request, code);
+ }
+
+ if (payload.action === "rotate") {
+ stage = "rotate";
+ const vault = await requireVault(request);
+ const recovery = generateRecoveryCode();
+ const hash = await hashRecoveryCode(recovery.raw);
+ await getD1()
+ .prepare("UPDATE vaults SET recovery_hash = ?1, updated_at = CURRENT_TIMESTAMP WHERE id = ?2")
+ .bind(hash, vault.id)
+ .run();
+ const response = noStoreJson({ recoveryCode: recovery.display });
+ return withSessionCookie(response, request, recovery.raw);
+ }
+
+ if (payload.action !== "create") {
+ throw new HttpError(400, "Unknown vault action.");
+ }
+
+ if (await accountHasVault(account.id)) {
+ throw new HttpError(409, "This account already has a connected world.");
+ }
+
+ const recovery = generateRecoveryCode();
+ stage = "create_validation";
+ const recoveryHash = await hashRecoveryCode(recovery.raw);
+ const vaultId = crypto.randomUUID();
+ const alias = cleanText(payload.profile?.alias, 30, "Shore Walker") || "Shore Walker";
+ const region = cleanText(payload.profile?.region, 60, "Not shared") || "Not shared";
+ const pressure = cleanText(payload.profile?.pressure, 800);
+ const ageBand = ageBands.has(payload.profile?.ageBand ?? "") ? payload.profile!.ageBand! : "";
+ const gender = genders.has(payload.profile?.gender ?? "") ? payload.profile!.gender! : "";
+ const mbtiCandidate = cleanText(payload.profile?.mbti, 4).toUpperCase();
+ const mbti = mbtiTypes.has(mbtiCandidate) ? mbtiCandidate : "";
+ const zodiac = zodiacSigns.has(payload.profile?.zodiac ?? "") ? payload.profile!.zodiac! : "";
+ const selfDescription = cleanText(payload.profile?.selfDescription, 1_200);
+ const repaymentPlan = cleanText(payload.profile?.repaymentPlan, 1_200);
+ const repaymentOutlook = repaymentOutlooks.has(payload.profile?.repaymentOutlook ?? "") ? payload.profile!.repaymentOutlook! : "";
+ const incomePlan = cleanText(payload.profile?.incomePlan, 800);
+ const countryCode = cleanText(payload.profile?.countryCode, 8).toUpperCase();
+ const countryName = cleanText(payload.profile?.countryName, 80);
+ const displayCurrency = /^[A-Z]{3}$/.test(payload.profile?.displayCurrency ?? "")
+ ? payload.profile!.displayCurrency!
+ : "CNY";
+ const monthlyIncome = cleanNumber(payload.profile?.monthlyIncome, 0, 1_000_000_000_000, 0);
+ const monthlyExpenses = cleanNumber(payload.profile?.monthlyExpenses, 0, 1_000_000_000_000, 0);
+ const positionX = cleanNumber(payload.position?.x, 6, 94, 47);
+ const positionY = cleanNumber(payload.position?.y, 12, 88, 63);
+ const locale = payload.locale === "en" ? "en" : "zh";
+ const discoveryConsent = payload.discoveryConsent === true ? 1 : 0;
+ const debts = Array.isArray(payload.debts)
+ ? payload.debts.slice(0, 30).map((item) => ({ ...validateDebt(item as import("@/lib/vault-server").DebtInput), id: crypto.randomUUID() }))
+ : [];
+ stage = "beta_rules";
+ const betaEnrollment = await consumeBetaInvite({
+ inviteCode: payload.inviteCode,
+ betaConsent: payload.betaConsent,
+ locale,
+ });
+ const db = getD1();
+ const statements = [
+ db
+ .prepare(
+ `INSERT INTO vaults
+ (id, recovery_hash, alias, region, pressure, age_band, gender, mbti, zodiac,
+ self_description, repayment_plan, repayment_outlook, income_plan, position_x, position_y, locale,
+ country_code, country_name, display_currency, monthly_income, monthly_expenses, discovery_consent)
+ VALUES (?1, ?2, ?3, ?4, ?5, ?6, ?7, ?8, ?9, ?10, ?11, ?12, ?13, ?14, ?15, ?16, ?17, ?18, ?19, ?20, ?21, ?22)`,
+ )
+ .bind(vaultId, recoveryHash, alias, region, pressure, ageBand, gender, mbti, zodiac, selfDescription, repaymentPlan, repaymentOutlook, incomePlan, positionX, positionY, locale, countryCode, countryName, displayCurrency, monthlyIncome, monthlyExpenses, discoveryConsent),
+ db.prepare(
+ "INSERT INTO account_vaults (account_id, vault_id) VALUES (?1, ?2)",
+ ).bind(account.id, vaultId),
+ ...(betaEnrollment ? [db.prepare(
+ `INSERT INTO beta_enrollments (id, vault_id, invite_digest, consent_version)
+ VALUES (?1, ?2, ?3, ?4)`,
+ ).bind(crypto.randomUUID(), vaultId, betaEnrollment.inviteDigest, betaEnrollment.consentVersion)] : []),
+ ...debts.map((debt) =>
+ db
+ .prepare(
+ `INSERT INTO debts
+ (id, vault_id, kind, custom_label, currency, original, balance, monthly, apr, minimum_payment, payment_status, remaining_months, due_day, method, sharing_mode, last_paid_at, payments)
+ VALUES (?1, ?2, ?3, ?4, ?5, ?6, ?7, ?8, ?9, ?10, ?11, ?12, ?13, ?14, ?15, ?16, ?17)`,
+ )
+ .bind(
+ debt.id,
+ vaultId,
+ debt.kind,
+ debt.customLabel,
+ debt.currency,
+ debt.original,
+ debt.balance,
+ debt.monthly,
+ debt.apr,
+ debt.minimumPayment,
+ debt.paymentStatus,
+ debt.remainingMonths,
+ debt.dueDay,
+ debt.method,
+ debt.sharingMode,
+ debt.lastPaidAt,
+ debt.payments,
+ ),
+ ),
+ ...debts.flatMap((debt) =>
+ debt.history.map((payment) =>
+ db
+ .prepare(
+ `INSERT INTO payment_records
+ (id, vault_id, debt_id, scheduled_date, confirmed_at, event_date, cash_payment, new_balance, source, income_type)
+ VALUES (?1, ?2, ?3, NULL, ?4, ?5, ?6, ?7, ?8, ?9)`,
+ )
+ .bind(
+ crypto.randomUUID(),
+ vaultId,
+ debt.id,
+ payment.confirmedAt,
+ payment.eventDate ?? payment.confirmedAt.slice(0, 10),
+ payment.cashPayment,
+ payment.newBalance,
+ payment.source ?? "self_report",
+ payment.incomeType ?? null,
+ ),
+ ),
+ ),
+ ];
+ stage = "create_batch";
+ await db.batch(statements);
+ stage = "create_readback";
+ const vault = await db
+ .prepare("SELECT * FROM vaults WHERE id = ?1")
+ .bind(vaultId)
+ .first();
+ if (!vault) throw new Error("Vault creation did not return a record.");
+ stage = "create_state";
+ const response = noStoreJson({
+ recoveryCode: recovery.display,
+ vault: await loadVaultState(vault),
+ }, { status: 201 });
+ return withSessionCookie(response, request, recovery.raw);
+ } catch (error) {
+ if (!(error instanceof HttpError)) {
+ const message = error instanceof Error ? error.message.slice(0, 300) : "Unknown vault storage failure";
+ console.error("Debt World vault request failed", { stage, message });
+ }
+ return routeError(error);
+ }
+}
+
+export async function PATCH(request: Request) {
+ try {
+ assertSameOrigin(request);
+ await ensureVaultStorageSchema();
+ const vault = await requireVault(request);
+ const payload = (await request.json()) as {
+ profile?: ProfileInput;
+ position?: { x?: number; y?: number };
+ locale?: string;
+ discoveryConsent?: boolean;
+ };
+ const alias = cleanText(payload.profile?.alias, 30, vault.alias) || vault.alias;
+ const region = cleanText(payload.profile?.region, 60, vault.region) || vault.region;
+ const pressure = cleanText(payload.profile?.pressure, 800, vault.pressure);
+ const ageBand = payload.profile?.ageBand === undefined ? vault.age_band : ageBands.has(payload.profile.ageBand) ? payload.profile.ageBand : "";
+ const gender = payload.profile?.gender === undefined ? vault.gender : genders.has(payload.profile.gender) ? payload.profile.gender : "";
+ const mbtiCandidate = cleanText(payload.profile?.mbti, 4, vault.mbti).toUpperCase();
+ const mbti = mbtiTypes.has(mbtiCandidate) ? mbtiCandidate : "";
+ const zodiac = payload.profile?.zodiac === undefined ? vault.zodiac : zodiacSigns.has(payload.profile.zodiac) ? payload.profile.zodiac : "";
+ const selfDescription = cleanText(payload.profile?.selfDescription, 1_200, vault.self_description);
+ const repaymentPlan = cleanText(payload.profile?.repaymentPlan, 1_200, vault.repayment_plan);
+ const repaymentOutlook = payload.profile?.repaymentOutlook === undefined ? vault.repayment_outlook : repaymentOutlooks.has(payload.profile.repaymentOutlook) ? payload.profile.repaymentOutlook : "";
+ const incomePlan = cleanText(payload.profile?.incomePlan, 800, vault.income_plan);
+ const countryCode = cleanText(payload.profile?.countryCode, 8, vault.country_code).toUpperCase();
+ const countryName = cleanText(payload.profile?.countryName, 80, vault.country_name);
+ const displayCurrency = typeof payload.profile?.displayCurrency === "string" && /^[A-Z]{3}$/.test(payload.profile.displayCurrency)
+ ? payload.profile.displayCurrency
+ : vault.display_currency;
+ const monthlyIncome = cleanNumber(payload.profile?.monthlyIncome, 0, 1_000_000_000_000, vault.monthly_income);
+ const monthlyExpenses = cleanNumber(payload.profile?.monthlyExpenses, 0, 1_000_000_000_000, vault.monthly_expenses);
+ const positionX = cleanNumber(payload.position?.x, 6, 94, vault.position_x);
+ const positionY = cleanNumber(payload.position?.y, 12, 88, vault.position_y);
+ const locale = payload.locale === "en" || payload.locale === "zh" ? payload.locale : vault.locale;
+ const discoveryConsent = payload.discoveryConsent === undefined
+ ? vault.discovery_consent
+ : payload.discoveryConsent === true ? 1 : 0;
+ await getD1()
+ .prepare(
+ `UPDATE vaults
+ SET alias = ?1, region = ?2, pressure = ?3, age_band = ?4, gender = ?5, mbti = ?6, zodiac = ?7,
+ self_description = ?8, repayment_plan = ?9, repayment_outlook = ?10, income_plan = ?11,
+ position_x = ?12, position_y = ?13, locale = ?14, country_code = ?15, country_name = ?16,
+ display_currency = ?17, monthly_income = ?18, monthly_expenses = ?19, discovery_consent = ?20,
+ updated_at = CURRENT_TIMESTAMP WHERE id = ?21`,
+ )
+ .bind(alias, region, pressure, ageBand, gender, mbti, zodiac, selfDescription, repaymentPlan, repaymentOutlook, incomePlan, positionX, positionY, locale, countryCode, countryName, displayCurrency, monthlyIncome, monthlyExpenses, discoveryConsent, vault.id)
+ .run();
+ return noStoreJson({ ok: true });
+ } catch (error) {
+ return routeError(error);
+ }
+}
+
+export async function DELETE(request: Request) {
+ try {
+ assertSameOrigin(request);
+ await ensureVaultStorageSchema();
+ const vault = await requireVault(request);
+ const payload = (await request.json()) as { confirm?: string };
+ if (payload.confirm !== "DELETE") {
+ throw new HttpError(400, "Type DELETE to permanently remove the vault.");
+ }
+ const db = getD1();
+ const link = await db.prepare(
+ "SELECT account_id FROM account_vaults WHERE vault_id = ?1 LIMIT 1",
+ ).bind(vault.id).first<{ account_id: string }>();
+ await db.batch([
+ db.prepare("DELETE FROM lucky_income_claims WHERE vault_id = ?1").bind(vault.id),
+ db.prepare("DELETE FROM payment_records WHERE vault_id = ?1").bind(vault.id),
+ db.prepare("DELETE FROM debts WHERE vault_id = ?1").bind(vault.id),
+ ...(link ? [
+ db.prepare("DELETE FROM account_sessions WHERE account_id = ?1").bind(link.account_id),
+ db.prepare("DELETE FROM account_vaults WHERE account_id = ?1").bind(link.account_id),
+ db.prepare("DELETE FROM accounts WHERE id = ?1").bind(link.account_id),
+ ] : []),
+ db.prepare("DELETE FROM vaults WHERE id = ?1").bind(vault.id),
+ ]);
+ return clearAccountSession(clearSessionCookie(noStoreJson({ deleted: true }), request), request);
+ } catch (error) {
+ return routeError(error);
+ }
+}
diff --git a/app/chatgpt-auth.ts b/app/chatgpt-auth.ts
new file mode 100644
index 0000000..8d1fb35
--- /dev/null
+++ b/app/chatgpt-auth.ts
@@ -0,0 +1,86 @@
+import { headers } from "next/headers";
+import { redirect } from "next/navigation";
+
+export type ChatGPTUser = {
+ displayName: string;
+ email: string;
+ fullName: string | null;
+};
+
+const USER_EMAIL_HEADER = "oai-authenticated-user-email";
+const USER_FULL_NAME_HEADER = "oai-authenticated-user-full-name";
+const USER_FULL_NAME_ENCODING_HEADER =
+ "oai-authenticated-user-full-name-encoding";
+const PERCENT_ENCODED_UTF8 = "percent-encoded-utf-8";
+const SIGN_IN_PATH = "/signin-with-chatgpt";
+const SIGN_OUT_PATH = "/signout-with-chatgpt";
+const CALLBACK_PATH = "/callback";
+
+export async function getChatGPTUser(): Promise {
+ const requestHeaders = await headers();
+ const email = requestHeaders.get(USER_EMAIL_HEADER);
+ if (!email) return null;
+
+ const encodedFullName = requestHeaders.get(USER_FULL_NAME_HEADER);
+ const fullName =
+ encodedFullName &&
+ requestHeaders.get(USER_FULL_NAME_ENCODING_HEADER) === PERCENT_ENCODED_UTF8
+ ? safeDecodeURIComponent(encodedFullName)
+ : null;
+
+ return {
+ displayName: fullName ?? email,
+ email,
+ fullName,
+ };
+}
+
+export async function requireChatGPTUser(
+ returnTo: string,
+): Promise {
+ const user = await getChatGPTUser();
+ if (user) return user;
+
+ redirect(chatGPTSignInPath(returnTo));
+}
+
+export function chatGPTSignInPath(returnTo: string): string {
+ const safeReturnTo = safeRelativeReturnPath(returnTo);
+ return `${SIGN_IN_PATH}?return_to=${encodeURIComponent(safeReturnTo)}`;
+}
+
+export function chatGPTSignOutPath(returnTo = "/"): string {
+ const safeReturnTo = safeRelativeReturnPath(returnTo);
+ return `${SIGN_OUT_PATH}?return_to=${encodeURIComponent(safeReturnTo)}`;
+}
+
+function safeRelativeReturnPath(value: string): string {
+ if (!value.startsWith("/") || value.startsWith("//")) return "/";
+
+ let url: URL;
+ try {
+ url = new URL(value, "https://app.local");
+ } catch {
+ return "/";
+ }
+ if (url.origin !== "https://app.local") return "/";
+ if (isReservedAuthPath(url.pathname)) return "/";
+
+ return `${url.pathname}${url.search}${url.hash}`;
+}
+
+function isReservedAuthPath(pathname: string): boolean {
+ return (
+ pathname === SIGN_IN_PATH ||
+ pathname === SIGN_OUT_PATH ||
+ pathname === CALLBACK_PATH
+ );
+}
+
+function safeDecodeURIComponent(value: string): string | null {
+ try {
+ return decodeURIComponent(value);
+ } catch {
+ return null;
+ }
+}
diff --git a/app/contribute/page.tsx b/app/contribute/page.tsx
new file mode 100644
index 0000000..4638399
--- /dev/null
+++ b/app/contribute/page.tsx
@@ -0,0 +1,10 @@
+import type { Metadata } from "next";
+import ContributePage from "../ContributePage";
+
+export const metadata: Metadata = {
+ title: "参与共建上岸星球 — 不会写代码也可以",
+ description: "通过地区债务分类、翻译校对、手机测试、隐私审核或代码贡献,共同建造真实、匿名、安全的全球债务世界。",
+ alternates: { canonical: "/contribute", languages: { "zh-CN": "/contribute", en: "/en/contribute" } },
+};
+
+export default function Page() { return ; }
diff --git a/app/en/about/page.tsx b/app/en/about/page.tsx
new file mode 100644
index 0000000..e938d72
--- /dev/null
+++ b/app/en/about/page.tsx
@@ -0,0 +1,10 @@
+import type { Metadata } from "next";
+import AboutPage from "../../AboutPage";
+
+export const metadata: Metadata = {
+ title: "What is Debt World? — A real, anonymous world of debt journeys",
+ description: "Learn how Debt World organizes mortgages, cards, student loans, and emerging debts, ties progress to real life, and grows an anonymous global debt map.",
+ alternates: { canonical: "/en/about", languages: { "zh-CN": "/about", en: "/en/about" } },
+};
+
+export default function Page() { return ; }
diff --git a/app/en/contribute/page.tsx b/app/en/contribute/page.tsx
new file mode 100644
index 0000000..e903334
--- /dev/null
+++ b/app/en/contribute/page.tsx
@@ -0,0 +1,10 @@
+import type { Metadata } from "next";
+import ContributePage from "../../ContributePage";
+
+export const metadata: Metadata = {
+ title: "Help build Debt World — no coding required",
+ description: "Contribute a regional debt category, translation review, device test, privacy review, or a small code change to the anonymous global debt world.",
+ alternates: { canonical: "/en/contribute", languages: { "zh-CN": "/contribute", en: "/en/contribute" } },
+};
+
+export default function Page() { return ; }
diff --git a/app/en/layout.tsx b/app/en/layout.tsx
new file mode 100644
index 0000000..e8ff869
--- /dev/null
+++ b/app/en/layout.tsx
@@ -0,0 +1,17 @@
+import type { Metadata } from "next";
+
+export const metadata: Metadata = {
+ title: "Debt World — A real-life debt simulation",
+ description: "Walk through an anonymous debt world where conversation turns multiple debts, real due dates, and real repayments into a living journey.",
+ alternates: {
+ canonical: "/en",
+ languages: {
+ "zh-CN": "/",
+ en: "/en",
+ },
+ },
+};
+
+export default function EnglishLayout({ children }: Readonly<{ children: React.ReactNode }>) {
+ return children;
+}
diff --git a/app/en/page.tsx b/app/en/page.tsx
new file mode 100644
index 0000000..f127865
--- /dev/null
+++ b/app/en/page.tsx
@@ -0,0 +1,13 @@
+import type { Metadata } from "next";
+import AccountGate from "../AccountGate";
+
+export const metadata: Metadata = {
+ title: "Debt World — A shared world for real repayment journeys",
+ description: "Walk through an anonymous debt world, organize multiple debts with Kian, and keep balances, due dates, and repayment progress tied to real life.",
+ alternates: { canonical: "/en", languages: { "zh-CN": "/", en: "/en" } },
+ openGraph: { title: "Debt World", description: "See the financial pressure behind ordinary lives—and the real steps people take toward shore.", url: "/en" },
+};
+
+export default function EnglishHome() {
+ return ;
+}
diff --git a/app/en/safety/page.tsx b/app/en/safety/page.tsx
new file mode 100644
index 0000000..ead62df
--- /dev/null
+++ b/app/en/safety/page.tsx
@@ -0,0 +1,10 @@
+import type { Metadata } from "next";
+import SafetyCenter from "../../SafetyCenter";
+
+export const metadata: Metadata = {
+ title: "Safety Center — Debt World",
+ description: "Debt World's privacy notice, community rules, deletion controls, and financial and legal boundaries.",
+ alternates: { canonical: "/en/safety", languages: { "zh-CN": "/safety", en: "/en/safety" } },
+};
+
+export default function EnglishSafetyPage() { return ; }
diff --git a/app/globals.css b/app/globals.css
new file mode 100644
index 0000000..5a87cea
--- /dev/null
+++ b/app/globals.css
@@ -0,0 +1,1606 @@
+@import "tailwindcss";
+
+:root {
+ --ink: #17201d;
+ --paper: #f3f0e6;
+ --acid: #d9f05d;
+ --coral: #e86e4e;
+ --blue: #7eb6ca;
+ --muted: #69716b;
+ --line: rgba(23, 32, 29, .17);
+ --font-ui: "Aptos", "Segoe UI", "Microsoft YaHei", "PingFang SC", system-ui, sans-serif;
+ --font-mono: "Cascadia Mono", "SFMono-Regular", Consolas, monospace;
+}
+
+/* Account entry and owner console */
+.account-shell { min-height: 100vh; display: grid; place-items: center; padding: 32px 18px; color: #173b45; background: radial-gradient(circle at 20% 15%, rgba(255,255,255,.9) 0 8%, transparent 30%), radial-gradient(circle at 80% 80%, rgba(216,242,214,.8), transparent 34%), linear-gradient(145deg, #dff4f0, #f8f0d8 52%, #e9ddf3); }
+.account-card { width: min(560px, 100%); padding: 40px; border: 1px solid rgba(27,80,86,.16); border-radius: 34px; background: rgba(255,255,255,.88); box-shadow: 0 30px 80px rgba(24,66,73,.17), inset 0 1px rgba(255,255,255,.95); backdrop-filter: blur(20px); text-align: center; }
+.account-planet { position: relative; width: 86px; height: 86px; margin: 0 auto 18px; display: grid; place-items: center; border-radius: 50%; color: #fff; background: linear-gradient(145deg, #267b7a, #6fb394); font-size: 48px; box-shadow: 0 12px 34px rgba(28,106,104,.25); }
+.account-planet i { position: absolute; width: 7px; height: 7px; border-radius: 50%; background: #eff57c; box-shadow: 0 0 14px #eff57c; }
+.account-planet i:nth-child(1) { top: 4px; right: 0; }.account-planet i:nth-child(2) { left: -8px; bottom: 18px; }.account-planet i:nth-child(3) { right: 8px; bottom: -4px; }
+.account-kicker { margin: 0 0 8px; color: #54817f; font: 800 13px/1.4 ui-monospace, monospace; letter-spacing: .14em; }
+.account-card h1 { margin: 0; color: #153d45; font-size: clamp(28px, 5vw, 42px); line-height: 1.12; letter-spacing: -.035em; }
+.account-lead { max-width: 470px; margin: 16px auto 26px; color: #557178; font-size: 17px; line-height: 1.7; }
+.account-beta-route { margin: -4px 0 22px; padding: 16px; border: 1px solid #cbded4; border-radius: 18px; color: #355d5a; background: linear-gradient(145deg,rgba(222,242,232,.76),rgba(247,244,215,.72)); text-align: left; }
+.account-beta-route > div { display: flex; align-items: center; gap: 9px; }.account-beta-route > div span { width: 30px; height: 30px; display: grid; place-items: center; border-radius: 10px; color: #effb9b; background: #245e5b; font: 900 15px ui-monospace,monospace; }.account-beta-route > div strong { color: #285b59; font-size: 15px; }
+.account-beta-route ol { display: grid; grid-template-columns: repeat(3,1fr); gap: 7px; margin: 13px 0 10px; padding: 0; list-style: none; }.account-beta-route li { min-height: 64px; display: flex; align-items: center; border-radius: 12px; background: rgba(255,255,255,.8); padding: 10px; color: #315f5d; font-size: 13px; font-weight: 800; line-height: 1.4; }.account-beta-route small { display: block; color: #67807d; font-size: 12px; line-height: 1.58; }
+.account-tabs { display: grid; grid-template-columns: 1fr 1fr; gap: 6px; padding: 5px; margin-bottom: 20px; border-radius: 16px; background: #edf3ef; }
+.account-tabs button { min-height: 48px; border: 0; border-radius: 12px; color: #668078; background: transparent; font-size: 15px; font-weight: 800; cursor: pointer; }
+.account-tabs button.active { color: #174d52; background: #fff; box-shadow: 0 5px 16px rgba(33,82,75,.12); }
+.account-form { display: grid; gap: 16px; text-align: left; }
+.account-form label > span { display: block; margin: 0 0 7px 4px; color: #365d61; font-size: 14px; font-weight: 800; }
+.account-form input, .account-recovery input { width: 100%; min-height: 54px; padding: 0 16px; border: 1px solid #c9dbd5; border-radius: 15px; outline: none; color: #173b45; background: rgba(255,255,255,.9); font-size: 16px; transition: .2s ease; }
+.account-form input:focus, .account-recovery input:focus { border-color: #4b9b91; box-shadow: 0 0 0 4px rgba(75,155,145,.12); }
+.account-import { display: flex; align-items: flex-start; gap: 10px; padding: 12px 14px; border-radius: 14px; background: #f2f7df; }
+.account-import input { width: 20px; min-height: 20px; margin-top: 2px; accent-color: #397f73; }
+.account-import span { margin: 0 !important; line-height: 1.55; }
+.account-primary, .account-secondary { width: 100%; min-height: 54px; border: 0; border-radius: 16px; font-size: 16px; font-weight: 900; cursor: pointer; }
+.account-primary { color: #fff; background: linear-gradient(135deg, #1e716f, #479985); box-shadow: 0 12px 26px rgba(31,113,107,.22); }
+.account-primary:disabled, .account-secondary:disabled { opacity: .55; cursor: wait; }
+.turnstile-wrap { min-height: 66px; display: grid; place-items: center; overflow: hidden; border: 1px solid rgba(49,110,104,.16); border-radius: 15px; background: rgba(241,248,244,.72); padding: 8px; }
+.turnstile-wrap > div { width: 100%; min-height: 48px; }
+.turnstile-wrap p { margin: 4px 0; color: #456a67; font-size: 14px; font-weight: 800; line-height: 1.5; text-align: center; }
+.turnstile-wrap p.turnstile-verified { color: #28704e; }
+.turnstile-wrap p.turnstile-failed { color: #a34937; }
+.account-secondary { margin-top: 12px; color: #29635f; background: #e4f1eb; }
+.account-text { margin: 18px auto 0; border: 0; color: #748c8c; background: transparent; text-decoration: underline; cursor: pointer; }
+.account-trust { display: flex; gap: 12px; margin: 22px 0 0; padding: 16px; border-radius: 16px; color: #55716b; background: #f5f7f2; text-align: left; }
+.account-trust > span { font-size: 24px; color: #3f867d; }.account-trust p { margin: 0; font-size: 13px; line-height: 1.6; }.account-trust strong { display: block; color: #2d5653; font-size: 14px; }
+.account-error { margin: 16px 0 0; padding: 12px; border-radius: 12px; color: #8f3e3e; background: #fff0ec; font-weight: 700; line-height: 1.5; }
+.account-card > footer { display: flex; justify-content: center; gap: 20px; margin-top: 22px; }.account-card > footer a { color: #547c7a; font-size: 13px; }
+.account-loading { display: grid; gap: 14px; place-items: center; }.account-loading span { font-size: 64px; color: #2f817a; animation: accountPulse 1.6s ease-in-out infinite; }.account-loading strong { font-size: 18px; }
+@keyframes accountPulse { 50% { transform: scale(1.08) rotate(8deg); opacity: .65; } }
+.account-shell:has(.entry-preview) { grid-template-columns: minmax(240px, 350px) minmax(470px, 560px) minmax(240px, 350px); gap: clamp(16px, 2.5vw, 34px); align-items: center; width: 100%; padding: 30px clamp(18px, 3vw, 52px); overflow: hidden; }
+.account-shell:has(.entry-preview) .account-card { width: 100%; position: relative; z-index: 3; }
+.entry-preview { position: relative; min-width: 0; min-height: 610px; display: flex; flex-direction: column; overflow: hidden; padding: 24px; border: 1px solid rgba(26,72,74,.16); border-radius: 30px; background: rgba(247,250,241,.72); box-shadow: 0 24px 60px rgba(24,66,73,.12), inset 0 1px rgba(255,255,255,.9); backdrop-filter: blur(18px); text-align: left; }
+.entry-preview::before { content: ""; position: absolute; width: 210px; height: 210px; border-radius: 50%; pointer-events: none; filter: blur(2px); opacity: .34; }
+.entry-preview-world::before { left: -92px; bottom: 34px; background: radial-gradient(circle, var(--acid), transparent 68%); }
+.entry-preview-plan::before { right: -90px; top: 110px; background: radial-gradient(circle, var(--blue), transparent 68%); }
+.entry-preview-heading { position: relative; z-index: 2; display: flex; align-items: center; gap: 11px; }
+.entry-preview-heading > span { width: 38px; height: 38px; display: grid; place-items: center; flex: 0 0 auto; border-radius: 12px; color: var(--acid); background: var(--ink); font: 900 12px var(--font-mono); }
+.entry-preview-heading > div { display: grid; gap: 3px; }.entry-preview-heading b { color: #204f53; font-size: 15px; line-height: 1.35; }.entry-preview-heading small { color: #6b8580; font: 800 10px var(--font-mono); letter-spacing: .09em; }
+.entry-preview h2 { position: relative; z-index: 2; margin: 22px 0 10px; color: #153d45; font-size: clamp(22px, 2.1vw, 30px); line-height: 1.14; letter-spacing: -.035em; }
+.entry-preview > p { position: relative; z-index: 2; margin: 0; color: #57716f; font-size: 14px; line-height: 1.75; }
+.entry-proof-row { position: relative; z-index: 2; display: flex; flex-wrap: wrap; gap: 7px; margin-top: auto; padding-top: 18px; }
+.entry-proof-row span { padding: 7px 9px; border: 1px solid rgba(42,81,78,.12); border-radius: 999px; color: #315e5a; background: rgba(255,255,255,.8); font-size: 11px; font-weight: 900; }
+.entry-world-scene { position: relative; z-index: 1; height: 270px; margin: 24px 0 0; overflow: hidden; border: 1px solid rgba(23,32,29,.12); border-radius: 24px; background: radial-gradient(circle at 72% 22%, rgba(217,240,93,.7), transparent 13%), linear-gradient(155deg,#bdd8cf,#eef0ce 52%,#c5dbe6); box-shadow: inset 0 0 50px rgba(255,255,255,.55); }
+.entry-world-scene::after { content: ""; position: absolute; inset: 0; background-image: radial-gradient(rgba(23,32,29,.16) .7px,transparent .7px); background-size: 13px 13px; opacity: .34; }
+.entry-road { position: absolute; z-index: 1; height: 32px; border-radius: 50%; border-top: 10px solid rgba(247,244,222,.82); transform: rotate(-20deg); }.entry-road-a { width: 320px; left: -36px; top: 125px; }.entry-road-b { width: 250px; right: -42px; top: 69px; transform: rotate(38deg); }
+.entry-district { position: absolute; z-index: 3; display: grid; gap: 3px; color: #294f4d; font-size: 22px; text-align: center; }.entry-district b { padding: 4px 7px; border-radius: 7px; background: rgba(255,255,255,.72); font: 900 8px var(--font-mono); }.entry-district-home { left: 24px; top: 31px; }.entry-district-card { right: 18px; bottom: 22px; }
+.entry-walker { position: absolute; z-index: 5; display: grid; place-items: center; animation: entry-walk 4.6s ease-in-out infinite; }.entry-walker i { width: 47px; height: 58px; display: grid; place-items: center; border: 5px solid #29342f; border-radius: 23px 23px 17px 17px; color: #fff; background: linear-gradient(#e88a66 0 54%,#6f98a7 55%); box-shadow: 0 9px 0 -5px rgba(23,32,29,.28); font-style: normal; }.entry-walker b { margin-top: 4px; padding: 4px 7px; border-radius: 999px; color: #fff; background: rgba(23,32,29,.84); font: 900 8px var(--font-mono); white-space: nowrap; }.entry-walker-one { left: 42%; top: 39%; }.entry-walker-two { right: 14%; top: 16%; animation-delay: -2.1s; transform: scale(.82); }
+.entry-debt-orbit { position: absolute; z-index: 6; padding: 7px 9px; border-radius: 10px; color: #fff; background: rgba(23,32,29,.9); box-shadow: 0 8px 18px rgba(23,32,29,.18); font: 900 8px var(--font-mono); animation: entry-label-float 3.2s ease-in-out infinite; }.entry-orbit-one { left: 13px; bottom: 49px; }.entry-orbit-two { right: 10px; top: 82px; animation-delay: -1.4s; }
+.entry-phone { position: relative; z-index: 1; width: min(286px, 92%); height: 336px; margin: 22px auto 0; padding: 17px 14px; border: 7px solid #1f2b27; border-radius: 34px; background: #f7f3e8; box-shadow: 0 20px 38px rgba(23,32,29,.18); transform: rotate(2deg); animation: entry-phone-breathe 5s ease-in-out infinite; }
+.entry-phone::before { content: ""; position: absolute; top: 6px; left: 50%; width: 50px; height: 5px; transform: translateX(-50%); border-radius: 999px; background: #1f2b27; }
+.entry-phone-top { display: flex; justify-content: space-between; align-items: center; margin-top: 8px; color: #294c4a; font: 900 10px var(--font-mono); }.entry-phone-top span { color: var(--coral); font-size: 20px; }
+.entry-cashflow { display: grid; gap: 5px; margin: 11px 0; padding: 11px; border-radius: 14px; color: #fff; background: #243a35; }.entry-cashflow small { color: #cae192; font: 800 8px var(--font-mono); }.entry-cashflow strong { font-size: 12px; }.entry-cashflow i { height: 5px; overflow: hidden; border-radius: 999px; background: rgba(255,255,255,.13); }.entry-cashflow i b { display: block; width: 66%; height: 100%; background: linear-gradient(90deg,var(--coral),var(--acid)); animation: entry-plan-progress 3.6s ease-in-out infinite; }
+.entry-plan-row { display: grid; grid-template-columns: 34px 1fr auto; gap: 9px; align-items: center; margin-top: 7px; padding: 9px; border: 1px solid #d9dfd2; border-radius: 13px; background: #fff; }.entry-plan-row > span { width: 34px; height: 34px; display: grid; place-items: center; border-radius: 10px; color: #fff; background: var(--coral); font: 900 11px var(--font-mono); }.entry-plan-row > div { display: grid; gap: 2px; }.entry-plan-row b { color: #254d4d; font-size: 11px; }.entry-plan-row small { color: #73827d; font-size: 8px; }.entry-plan-row em { color: #588580; font-style: normal; }
+.entry-kian-bubble { display: grid; grid-template-columns: 35px 1fr; gap: 8px; align-items: center; margin-top: 9px; padding: 9px; border-radius: 14px; background: #e7efc1; }.entry-kian-bubble > span { font-size: 27px; filter: drop-shadow(0 3px 2px rgba(23,32,29,.13)); }.entry-kian-bubble p { margin: 0; color: #43564e; font-size: 8px; line-height: 1.45; }.entry-kian-bubble p b { display: block; color: #2b514c; font-size: 10px; }
+@keyframes entry-walk { 0%,100% { transform: translate3d(-5px,0,0) rotate(-1deg); } 50% { transform: translate3d(12px,-7px,0) rotate(2deg); } }
+@keyframes entry-label-float { 50% { transform: translateY(-7px); } }
+@keyframes entry-phone-breathe { 50% { transform: rotate(-1deg) translateY(-4px); } }
+@keyframes entry-plan-progress { 0%,100% { width: 58%; } 50% { width: 76%; } }
+@media (max-width: 1180px) {
+ .account-shell:has(.entry-preview) { grid-template-columns: minmax(0,1fr) minmax(460px,560px); align-items: start; overflow: visible; }
+ .account-card { grid-column: 2; grid-row: 1 / span 2; position: sticky !important; top: 22px; }
+ .entry-preview { min-height: 420px; }.entry-preview-plan { grid-column: 1; }.entry-world-scene { height: 205px; }.entry-phone { height: 286px; }.entry-preview h2 { margin-top: 16px; }
+}
+@media (max-width: 820px) {
+ .account-shell:has(.entry-preview) { display: flex; flex-direction: column; padding: 14px 10px 38px; overflow: visible; }
+ .account-card { order: 1; position: relative !important; top: auto; padding: 30px 20px; }.entry-preview { width: 100%; min-height: auto; padding: 20px; }.entry-preview-world { order: 2; }.entry-preview-plan { order: 3; }.entry-world-scene { height: 235px; }.entry-phone { height: 315px; }.entry-preview > p { font-size: 15px; }.entry-preview h2 { font-size: 25px; }
+}
+@media (prefers-reduced-motion: reduce) { .entry-walker,.entry-debt-orbit,.entry-phone,.entry-cashflow i b { animation: none !important; } }
+.account-link-card { text-align: center; }.account-link-card .account-primary { margin-top: 2px; }.account-divider { display: flex; align-items: center; gap: 12px; margin: 22px 0; color: #7a918e; font-size: 13px; }.account-divider::before,.account-divider::after { content:""; flex: 1; height: 1px; background: #d9e4df; }
+.account-recovery { display: grid; grid-template-columns: 1fr auto; gap: 9px; }.account-recovery button { padding: 0 20px; border: 0; border-radius: 14px; color: #fff; background: #397f76; font-weight: 900; cursor: pointer; }
+.account-next-note { margin: 13px 2px 0; color: #667f7b; font-size: 13px; font-weight: 700; line-height: 1.6; }
+.account-chip { position: fixed; z-index: 120; right: 16px; bottom: 14px; display: grid; grid-template-columns: auto auto auto auto; gap: 8px; align-items: center; padding: 8px 9px 8px 12px; border: 1px solid rgba(255,255,255,.5); border-radius: 999px; color: #244f50; background: rgba(255,255,255,.88); box-shadow: 0 10px 30px rgba(31,61,63,.18); backdrop-filter: blur(16px); }.account-chip > span { color: #52a774; font-size: 11px; }.account-chip b { font-size: 13px; }.account-chip small { color: #76908b; font: 10px ui-monospace, monospace; }.account-chip button { border: 0; border-radius: 999px; padding: 7px 10px; color: #456c68; background: #e8f1ed; font-size: 12px; font-weight: 800; cursor: pointer; }
+.admin-page-link { display: inline-flex; align-items: center; justify-content: center; text-decoration: none; }
+
+.owner-admin-shell { min-height: 100vh; padding: 34px clamp(18px, 4vw, 64px) 80px; color: #163c45; background: #edf2eb; background-image: linear-gradient(rgba(38,83,80,.04) 1px, transparent 1px), linear-gradient(90deg, rgba(38,83,80,.04) 1px, transparent 1px); background-size: 28px 28px; }
+.owner-admin-top { display: flex; justify-content: space-between; gap: 24px; align-items: flex-end; max-width: 1500px; margin: 0 auto 28px; }.owner-admin-top p,.owner-panel > header p { margin: 0 0 5px; color: #5a8580; font: 800 12px ui-monospace, monospace; letter-spacing: .13em; }.owner-admin-top h1 { margin: 0; font-size: clamp(32px, 5vw, 56px); letter-spacing: -.045em; }.owner-admin-top span { color: #65807f; font-size: 14px; }.owner-admin-top nav { display: flex; flex-wrap: wrap; gap: 8px; }.owner-admin-top nav a,.owner-admin-top nav button { min-height: 42px; display: inline-flex; align-items: center; padding: 0 15px; border: 1px solid #c4d4ce; border-radius: 12px; color: #315d5b; background: rgba(255,255,255,.7); font-size: 13px; font-weight: 800; text-decoration: none; cursor: pointer; }
+.owner-live-state { display: block; margin-top: 7px; color: #6c8985; font: 800 11px ui-monospace,monospace; letter-spacing: .04em; }.owner-admin-top nav .owner-auto-button.active { color: #286b57; border-color: #9bc9b5; background: #e1f3e8; }
+.owner-metrics { max-width: 1500px; margin: 0 auto 16px; display: grid; grid-template-columns: repeat(4,1fr); gap: 12px; }.owner-metrics article { min-height: 146px; display: flex; flex-direction: column; justify-content: space-between; padding: 21px; border: 1px solid #cddbd4; border-radius: 22px; background: rgba(255,255,255,.82); box-shadow: 0 10px 30px rgba(36,76,72,.06); }.owner-metrics span { color: #607c79; font-size: 14px; font-weight: 800; }.owner-metrics strong { color: #184f53; font-size: clamp(32px,4vw,48px); letter-spacing: -.045em; }.owner-metrics small { color: #7c928e; }.owner-metrics .needs-attention { border-color: #e3ad80; background: #fff8eb; }.owner-metrics .needs-attention strong { color: #a85f35; }
+.owner-signups { max-width: 1500px; margin: 0 auto 16px; display: flex; justify-content: space-between; gap: 20px; align-items: center; padding: 17px 20px; border-radius: 18px; background: #d9ebe2; }.owner-signups > div { display: flex; align-items: center; gap: 13px; }.owner-signups i { width: 12px; height: 12px; border-radius: 50%; background: #4aa879; box-shadow: 0 0 0 6px rgba(74,168,121,.13); }.owner-signups span { display: grid; }.owner-signups strong { font-size: 15px; }.owner-signups small { color: #69837e; margin-top: 3px; }.owner-signups button { min-height: 42px; padding: 0 17px; border: 0; border-radius: 12px; color: #fff; background: #2e756c; font-weight: 900; cursor: pointer; }.owner-signups.paused { background: #f4dfd3; }.owner-signups.paused i { background: #bd6b51; box-shadow: 0 0 0 6px rgba(189,107,81,.13); }
+.owner-signup-actions { display: flex; flex-wrap: wrap; justify-content: flex-end; gap: 8px; }.owner-signups .owner-moderation-button { color: #315f5b; border: 1px solid #aac9bf; background: rgba(255,255,255,.76); }
+.owner-panel { max-width: 1500px; margin: 16px auto 0; overflow: hidden; border: 1px solid #ccd9d3; border-radius: 24px; background: rgba(255,255,255,.86); box-shadow: 0 14px 40px rgba(36,76,72,.06); }.owner-panel > header { display: flex; justify-content: space-between; align-items: flex-end; gap: 20px; padding: 24px; border-bottom: 1px solid #dce5e0; }.owner-panel h2 { margin: 0; font-size: 26px; }.owner-panel > header span { display: block; margin-top: 5px; color: #708985; font-size: 13px; }
+.owner-data-state { min-height: 190px; display: flex; align-items: center; justify-content: center; gap: 18px; padding: 28px; text-align: left; }.owner-data-state > b { width: 54px; height: 54px; flex: 0 0 auto; display: grid; place-items: center; border-radius: 50%; background: var(--ink); color: var(--acid); font-size: 22px; }.owner-data-state h2,.owner-data-state p { margin: 0; }.owner-data-state p { margin-top: 7px; color: var(--muted); }.owner-data-state > button { border: 1px solid var(--ink); background: var(--acid); padding: 10px 15px; font-weight: 900; cursor: pointer; }
+.owner-launch-panel > header > a { min-height: 42px; display: inline-flex; align-items: center; flex: 0 0 auto; padding: 0 15px; border-radius: 12px; color: #fff; background: #286d68; text-decoration: none; font-size: 13px; font-weight: 900; }
+.owner-launch-grid { display: grid; grid-template-columns: .85fr 1.1fr 1.1fr; gap: 12px; padding: 20px 20px 14px; }.owner-launch-grid article { min-width: 0; border: 1px solid #d5e0db; border-radius: 18px; background: #f8faf7; padding: 17px; }.owner-public-link { display: flex; flex-direction: column; gap: 10px; background: linear-gradient(145deg,#e6f2eb,#f6f3d9) !important; }.owner-public-link > span,.owner-invite-copy span { color: #597873; font-size: 12px; font-weight: 900; letter-spacing: .04em; }.owner-public-link strong { overflow-wrap: anywhere; color: #225b59; font-size: 18px; line-height: 1.45; }.owner-public-link small { color: #6c837f; font-size: 12px; line-height: 1.6; }.owner-public-link button,.owner-invite-copy button { min-height: 40px; border: 1px solid #aebfba; border-radius: 11px; color: #2f6561; background: #fff; padding: 8px 12px; font-size: 12px; font-weight: 900; cursor: pointer; }.owner-public-link button { margin-top: auto; }
+.owner-invite-copy { display: flex; flex-direction: column; gap: 11px; }.owner-invite-copy > div { display: flex; justify-content: space-between; align-items: center; gap: 10px; }.owner-invite-copy p { max-height: 186px; margin: 0; overflow-y: auto; white-space: pre-wrap; color: #526e6a; font-size: 12px; line-height: 1.65; }
+.owner-funnel { display: grid; grid-template-columns: 1fr auto 1fr auto 1fr auto 1fr; align-items: center; gap: 10px; margin: 0 20px 14px; padding: 17px; border-radius: 18px; color: #315b58; background: #eef4ef; }.owner-funnel > div { display: grid; grid-template-columns: auto 1fr; grid-template-rows: auto auto; column-gap: 10px; align-items: center; }.owner-funnel > div > span { grid-row: 1/3; width: 29px; height: 29px; display: grid; place-items: center; border-radius: 50%; color: #fff; background: #4d847b; font: 900 12px ui-monospace,monospace; }.owner-funnel strong { font-size: 22px; line-height: 1; }.owner-funnel small { color: #718682; font-size: 11px; }.owner-funnel > i { color: #8da09b; font-style: normal; }
+.owner-launch-note { margin: 0 20px 20px; border-left: 4px solid #d0a742; border-radius: 8px; background: #fff6d9; color: #715d2e; padding: 11px 13px; font-size: 13px; font-weight: 800; line-height: 1.55; }
+.owner-source-links { display: grid; grid-template-columns: repeat(4,minmax(0,1fr)); gap: 10px; padding: 18px 20px; }.owner-source-links article { min-width: 0; display: grid; gap: 9px; padding: 15px; border: 1px solid #d5e1db; border-radius: 16px; background: linear-gradient(145deg,#f8fbf8,#edf4ef); }.owner-source-links span { color: #315e5a; font-size: 14px; font-weight: 900; }.owner-source-links code { min-height: 34px; overflow-wrap: anywhere; color: #708983; font-size: 10px; line-height: 1.45; }.owner-source-links button { min-height: 37px; border: 1px solid #abc4bb; border-radius: 10px; color: #326a63; background: #fff; font-size: 12px; font-weight: 900; cursor: pointer; }
+.owner-source-stats { display: grid; grid-template-columns: repeat(3,minmax(0,1fr)); gap: 10px; padding: 0 20px 20px; }.owner-source-stat { padding: 15px; border: 1px solid #d8e2dd; border-radius: 16px; background: #fbfcfa; }.owner-source-stat > header { display: flex; justify-content: space-between; gap: 12px; align-items: center; }.owner-source-stat > header strong { color: #2d5956; font-size: 14px; }.owner-source-stat > header b { color: #2e7567; font-size: 18px; }.owner-source-funnel { display: flex; flex-wrap: wrap; gap: 6px; align-items: center; margin-top: 11px; }.owner-source-funnel span { padding: 5px 7px; border-radius: 8px; color: #56726e; background: #edf3ef; font-size: 11px; font-weight: 800; }.owner-source-funnel i { color: #9aaba6; font-size: 10px; font-style: normal; }
+.owner-user-filters { display: flex; gap: 8px; }.owner-user-filters input,.owner-user-filters select { min-height: 44px; padding: 0 13px; border: 1px solid #cbd8d3; border-radius: 12px; color: #274e50; background: #f8faf7; font-size: 14px; }.owner-user-filters input { width: 240px; }
+.owner-account-filter { display: flex; gap: 7px; padding: 13px 24px; border-bottom: 1px solid #e4ebe7; background: #f8faf7; }.owner-account-filter button { min-height: 34px; padding: 0 12px; border: 1px solid #ccd9d4; border-radius: 999px; color: #5f7a76; background: #fff; font-size: 12px; font-weight: 800; cursor: pointer; }.owner-account-filter button.active { color: #fff; border-color: #387870; background: #387870; }
+.owner-user-list { overflow-x: auto; }.owner-user-row { min-width: 1030px; display: grid; grid-template-columns: 1.05fr .9fr .72fr 1.55fr .58fr; gap: 16px; align-items: center; padding: 17px 24px; border-bottom: 1px solid #e4ebe7; }.owner-user-row:last-child { border-bottom: 0; }.owner-user-row > div { display: grid; gap: 4px; }.owner-user-row strong { color: #284f51; font-size: 15px; }.owner-user-row code { color: #75908b; font-size: 11px; }.owner-user-row small { color: #81948f; }.owner-user-head { color: #78908b; background: #f3f6f2; font-size: 11px; font-weight: 900; letter-spacing: .08em; }.owner-user-row em { width: max-content; padding: 4px 8px; border-radius: 999px; font-size: 11px; font-style: normal; font-weight: 800; }.status-linked,.status-active { color: #33715d; background: #dff0e4; }.status-account_only { color: #746330; background: #f4ebc9; }.status-legacy { color: #8c5945; background: #f3dfd6; }.status-suspended { color: #9b473e; background: #f8dcd7; }.owner-usage-pills { display: flex !important; flex-wrap: wrap; gap: 5px !important; }.owner-usage-pills span { padding: 5px 8px; border-radius: 8px; color: #456765; background: #edf3ef; font-size: 11px; font-weight: 800; }.owner-user-actions button { min-height: 36px; border-radius: 10px; padding: 0 11px; font-size: 11px; font-weight: 900; cursor: pointer; }.owner-user-actions .suspend { color: #984f45; border: 1px solid #dfb6ae; background: #fff3f0; }.owner-user-actions .restore { color: #2f715c; border: 1px solid #a9cdbd; background: #edf8f2; }
+.owner-feedback-grid { display: grid; grid-template-columns: repeat(2,minmax(0,1fr)); gap: 12px; padding: 18px; }.owner-feedback-grid > article { padding: 18px; border: 1px solid #d9e2dc; border-radius: 17px; background: #fbfcfa; }.owner-feedback-grid > article.resolved { opacity: .62; }.owner-feedback-grid article > header { display: flex; justify-content: space-between; gap: 10px; }.owner-feedback-grid header div { display: grid; }.owner-feedback-grid code { color: #81938e; font-size: 10px; }.owner-feedback-grid b { color: #d7963f; letter-spacing: 2px; }.owner-feedback-grid p { min-height: 50px; color: #3b5b5d; line-height: 1.65; white-space: pre-wrap; }.owner-feedback-grid footer { display: flex; justify-content: space-between; gap: 12px; align-items: center; }.owner-feedback-grid footer span { color: #82938f; font-size: 11px; }.owner-feedback-grid footer button { border: 0; border-radius: 9px; padding: 8px 10px; color: #fff; background: #438079; font-weight: 800; cursor: pointer; }.owner-feedback-grid footer button.reopen { color: #426763; background: #e7efeb; }.owner-feedback-grid footer em { color: #52806e; font-size: 12px; font-style: normal; font-weight: 800; }
+.owner-empty { padding: 32px; color: #78908c; text-align: center; }.owner-loading,.owner-message { position: fixed; z-index: 20; right: 24px; bottom: 24px; padding: 13px 18px; border-radius: 14px; color: #fff; background: #295e5e; box-shadow: 0 12px 34px rgba(21,65,64,.25); font-weight: 800; }.owner-message { bottom: 76px; background: #9a593d; }
+.owner-activation-card,.owner-admin-denied { width: min(560px,100%); margin: 8vh auto 0; padding: 42px; border: 1px solid #cbd9d2; border-radius: 28px; background: rgba(255,255,255,.9); box-shadow: 0 24px 70px rgba(28,68,65,.12); text-align: center; }.owner-lock { width: 78px; height: 78px; display: grid; place-items: center; margin: 0 auto 17px; border-radius: 26px; color: #fff; background: #286c68; font-size: 38px; }.owner-activation-card > p:first-of-type { color: #5b827e; font: 800 12px ui-monospace,monospace; letter-spacing: .12em; }.owner-activation-card h1,.owner-admin-denied h1 { margin: 7px 0 10px; font-size: 38px; }.owner-activation-card > span { display: inline-block; padding: 7px 11px; border-radius: 999px; color: #426965; background: #e7f0eb; font-size: 13px; }.owner-activation-card > p:not(:first-of-type) { color: #627d79; line-height: 1.7; }.owner-activation-card > button { width: 100%; min-height: 52px; margin: 12px 0; border: 0; border-radius: 14px; color: #fff; background: #2d776f; font-size: 16px; font-weight: 900; cursor: pointer; }.owner-activation-card small { display: block; color: #718984; line-height: 1.6; }.owner-activation-card em { display: block; margin: 14px 0; color: #9c543b; font-style: normal; }.owner-activation-card > a { display: inline-block; margin-top: 18px; color: #527875; }.owner-admin-denied span { color: #be765d; font: 900 54px ui-monospace,monospace; }.owner-admin-denied p { color: #6c817e; }.owner-admin-denied a { display: inline-block; margin-top: 14px; padding: 11px 17px; border-radius: 12px; color: #fff; background: #347870; text-decoration: none; font-weight: 800; }
+
+@media (max-width: 1100px) { .owner-launch-grid { grid-template-columns: 1fr 1fr; }.owner-public-link { grid-column: 1/-1; }.owner-funnel { grid-template-columns: 1fr 1fr; }.owner-funnel > i { display: none; }.owner-source-links { grid-template-columns: repeat(3,minmax(0,1fr)); }.owner-source-stats { grid-template-columns: repeat(2,minmax(0,1fr)); } }
+@media (max-width: 900px) { .owner-admin-top { align-items: flex-start; flex-direction: column; }.owner-metrics { grid-template-columns: repeat(2,1fr); }.owner-panel > header { align-items: flex-start; flex-direction: column; }.owner-user-filters { width: 100%; flex-wrap: wrap; }.owner-user-filters input { flex: 1 1 100%; width: auto; }.owner-user-filters select { flex: 1; }.owner-feedback-grid { grid-template-columns: 1fr; }.owner-source-links { grid-template-columns: repeat(2,minmax(0,1fr)); } }
+@media (max-width: 560px) { .account-card { padding: 28px 20px; border-radius: 25px; }.account-beta-route ol { grid-template-columns: 1fr; }.account-beta-route li { min-height: 44px; }.account-chip { left: 10px; right: 10px; justify-content: center; }.account-chip small { display: none; }.owner-admin-shell { padding: 24px 12px 70px; }.owner-admin-top nav { width: 100%; }.owner-admin-top nav a,.owner-admin-top nav button { flex: 1 1 calc(50% - 8px); justify-content: center; }.owner-metrics { grid-template-columns: 1fr 1fr; gap: 8px; }.owner-metrics article { min-height: 122px; padding: 15px; }.owner-metrics strong { font-size: 30px; }.owner-signups { align-items: flex-start; flex-direction: column; }.owner-signup-actions,.owner-signup-actions button { width: 100%; }.owner-launch-grid { grid-template-columns: 1fr; padding: 12px; }.owner-public-link { grid-column: auto; }.owner-funnel { grid-template-columns: 1fr 1fr; margin: 0 12px 12px; }.owner-launch-note { margin: 0 12px 14px; }.owner-source-links,.owner-source-stats { grid-template-columns: 1fr; padding-left: 12px; padding-right: 12px; }.owner-user-filters { flex-direction: column; }.owner-user-filters input,.owner-user-filters select { width: 100%; }.owner-activation-card,.owner-admin-denied { padding: 30px 20px; }.owner-feedback-grid { padding: 10px; } }
+
+.referral-card { margin: 18px 0; padding: 18px; border: 1px solid rgba(217,240,93,.42); border-radius: 22px; background: linear-gradient(145deg,rgba(217,240,93,.12),rgba(105,168,162,.08)); }
+.referral-card > header { display: flex; align-items: center; justify-content: space-between; gap: 12px; }
+.referral-card > header div { display: flex; align-items: center; gap: 9px; }
+.referral-card > header div > span { display: grid; place-items: center; width: 34px; height: 34px; border-radius: 50%; color: #1d4e49; background: #d9f05d; font-size: 18px; }
+.referral-card > header strong { color: #173f3c; font-size: 17px; }
+.referral-card code { padding: 6px 9px; border-radius: 9px; background: rgba(22,62,59,.08); color: #35665f; font-size: 12px; font-weight: 800; }
+.referral-card > p,.referral-card > small { display: block; margin: 10px 0; color: #5b716d; line-height: 1.65; }
+.referral-rewards { display: flex; flex-wrap: wrap; align-items: center; gap: 8px; margin: 12px 0; }
+.referral-rewards span { display: inline-flex; align-items: baseline; gap: 4px; padding: 7px 10px; border-radius: 999px; background: rgba(255,255,255,.78); color: #55706b; font-size: 12px; }
+.referral-rewards b { color: #2a6159; font-size: 15px; }
+.referral-rewards i { color: #81968f; }
+.referral-stats { display: grid; grid-template-columns: repeat(3,1fr); gap: 8px; margin: 12px 0; }
+.referral-stats span { display: flex; flex-direction: column; align-items: center; padding: 10px; border-radius: 14px; background: rgba(255,255,255,.65); color: #72847f; font-size: 11px; }
+.referral-stats strong { color: #164b46; font-size: 22px; }
+.referral-copy { width: 100%; min-height: 44px; border: 0; border-radius: 14px; background: #1e544e; color: #fff; font-weight: 850; cursor: pointer; }
+.owner-traffic-list { padding: 6px 24px 24px; overflow-x: auto; }
+.owner-traffic-row { min-width: 720px; display: grid; grid-template-columns: 1.35fr repeat(5,1fr); align-items: center; gap: 12px; min-height: 50px; padding: 0 14px; border-bottom: 1px solid #dfe7e3; color: #466963; }
+.owner-traffic-row > span { text-align: center; font-weight: 750; }
+.owner-traffic-row > strong { color: #234f4b; font-size: 13px; }
+.owner-traffic-head { border-radius: 13px; background: #edf4f1; color: #6a807c; font-size: 12px; }
+.owner-traffic-head > span:first-child { text-align: left; }
+@media (max-width: 560px) { .referral-card > header { align-items: flex-start; flex-direction: column; }.referral-stats { grid-template-columns: repeat(3,1fr); } }
+
+.about-shell { min-height: 100vh; padding: 0 clamp(20px,5vw,80px) 70px; color: #173f3c; background: radial-gradient(circle at 12% 10%,rgba(217,240,93,.24),transparent 28%),linear-gradient(160deg,#f5f2e7,#e6f0eb 55%,#d7e9e3); }
+.about-shell > nav { max-width: 1240px; min-height: 76px; margin: 0 auto; display: flex; align-items: center; justify-content: space-between; border-bottom: 1px solid rgba(23,63,60,.14); }
+.about-shell > nav a { color: #173f3c; font-weight: 850; text-decoration: none; }
+.about-hero { max-width: 1000px; margin: 0 auto; padding: clamp(70px,12vw,150px) 0 clamp(58px,8vw,100px); text-align: center; }
+.about-hero > p,.about-debts > p,.about-faq > p { color: #64817c; font-size: 12px; font-weight: 900; letter-spacing: .18em; }
+.about-hero h1 { max-width: 900px; margin: 18px auto; font-size: clamp(42px,7vw,82px); line-height: 1.02; letter-spacing: -.055em; }
+.about-hero > span { display: block; max-width: 780px; margin: 0 auto; color: #58716c; font-size: clamp(17px,2vw,22px); line-height: 1.75; }
+.about-hero > a { display: inline-flex; margin-top: 32px; padding: 15px 23px; border-radius: 999px; background: #173f3c; color: #fff; font-weight: 850; text-decoration: none; box-shadow: 0 15px 35px rgba(23,63,60,.18); }
+.about-principles { max-width: 1240px; margin: 0 auto; display: grid; grid-template-columns: repeat(2,1fr); gap: 14px; }
+.about-principles article { min-height: 245px; padding: 28px; border: 1px solid rgba(23,63,60,.12); border-radius: 28px; background: rgba(255,255,255,.56); }
+.about-principles b { color: #7d9c95; font-size: 13px; }.about-principles h2 { margin: 38px 0 12px; font-size: clamp(23px,3vw,34px); }.about-principles p { margin: 0; color: #617772; font-size: 16px; line-height: 1.8; }
+.about-debts,.about-faq { max-width: 1240px; margin: 85px auto 0; }.about-debts h2,.about-faq h2 { margin: 12px 0 26px; font-size: clamp(30px,4vw,48px); letter-spacing: -.035em; }
+.about-debts > div { display: flex; flex-wrap: wrap; gap: 10px; }.about-debts span { padding: 10px 14px; border: 1px solid #afc6bf; border-radius: 999px; background: rgba(255,255,255,.5); font-weight: 700; }
+.about-faq details { border-top: 1px solid rgba(23,63,60,.18); padding: 20px 2px; }.about-faq details:last-of-type { border-bottom: 1px solid rgba(23,63,60,.18); }.about-faq summary { cursor: pointer; font-size: 18px; font-weight: 850; }.about-faq details p { max-width: 900px; color: #607773; line-height: 1.8; }
+.about-shell > footer { max-width: 1240px; margin: 80px auto 0; display: flex; align-items: center; justify-content: space-between; gap: 16px; }.about-shell > footer a { color: #285b55; font-weight: 800; }
+@media (max-width: 700px) { .about-principles { grid-template-columns: 1fr; }.about-principles article { min-height: auto; }.about-principles h2 { margin-top: 24px; }.about-shell > footer { align-items: flex-start; flex-direction: column; } }
+
+/* Individualized walkers and an expandable world */
+.rotating-slogan { animation: slogan-arrive .5s ease both; max-width: 420px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
+@keyframes slogan-arrive { from { opacity: 0; transform: translateY(4px); } }
+.kian-pet-button { min-width: 156px !important; display: grid !important; grid-template-columns: 48px 1fr; grid-template-rows: auto auto; gap: 0 7px !important; align-items: center; padding: 5px 12px 5px 6px !important; border-color: rgba(255,215,91,.5) !important; background: linear-gradient(145deg, rgba(255,236,155,.16), rgba(255,255,255,.07)) !important; text-align: left; }
+.kian-pet-button .golden-dog { position: relative; grid-row: 1/3; width: 46px; height: 40px; display: grid; place-items: center; border-radius: 16px; background: linear-gradient(145deg,#ffe27b,#d99d28); font-size: 25px; box-shadow: 0 6px 15px rgba(246,190,50,.24); animation: kian-dog-float 2.6s ease-in-out infinite; }
+.golden-dog i { position: absolute; right: -5px; bottom: -3px; padding: 2px 4px; border: 1px solid #ffec98; border-radius: 4px; color: #6b4500; background: linear-gradient(#ffe77c,#dca52c); font: 900 7px var(--font-mono); }
+.kian-pet-button b { align-self: end; color: #fff2ad; font-size: 13px; }.kian-pet-button small { align-self: start; color: rgba(255,255,255,.63); font-size: 9px; }
+.shore-reward-meter { display: grid; grid-template-columns: 1fr 1fr; gap: 7px; padding: 14px 0; border-bottom: 1px solid rgba(255,255,255,.11); }
+.shore-reward-meter > div { display: grid; gap: 3px; border: 1px solid rgba(217,240,93,.2); border-radius: 11px; background: rgba(217,240,93,.07); padding: 9px; }
+.shore-reward-meter span { color: #e8f887; font-size: 9px; font-weight: 900; letter-spacing: .04em; }
+.shore-reward-meter strong { color: #fff; font: 900 18px var(--font-mono); }
+.shore-reward-meter small { grid-column: 1/-1; color: rgba(243,240,230,.58); font-size: 10px; line-height: 1.5; }
+@keyframes kian-dog-float { 50% { transform: translateY(-3px) rotate(-2deg); } }
+
+.world-canvas { position: absolute; z-index: 1; left: -27%; top: -27%; width: 154%; height: 154%; transform-origin: center; touch-action: none; cursor: grab; transition: transform .16s ease-out; }
+.world-canvas.is-dragging { cursor: grabbing; transition: none; }
+.world-zoom-controls { position: absolute; z-index: 35; right: 15px; bottom: 15px; display: flex; align-items: center; gap: 5px; padding: 6px; border: 1px solid rgba(255,255,255,.65); border-radius: 15px; background: rgba(28,39,35,.86); color: #fff; box-shadow: 0 10px 28px rgba(23,32,29,.22); backdrop-filter: blur(12px); }
+.world-zoom-controls button { min-width: 35px; height: 34px; padding: 0 9px; border: 0; border-radius: 10px; color: #f6f5df; background: rgba(255,255,255,.1); font-weight: 900; cursor: pointer; }.world-zoom-controls button:last-child { color: var(--ink); background: var(--acid); font-size: 10px; }.world-zoom-controls span { min-width: 45px; text-align: center; font: 800 10px var(--font-mono); }
+.world-stage > .light-feedback-toast,.world-stage > .mobile-controls { z-index: 40; }
+
+.character-avatar.body-burdened .character-torso { left: 1px; width: 54px; height: 37px; border-radius: 52% 52% 25% 25%; }.character-avatar.body-burdened .character-legs { left: 11px; width: 34px; }.character-avatar.body-burdened .character-head { transform: translateY(3px); }
+.character-avatar.body-light .character-torso { left: 8px; width: 40px; }.character-avatar.body-light .character-legs { left: 15px; width: 26px; }.character-avatar.body-light .character-legs i { height: 21px; }
+.character-avatar.body-rising .character-torso { left: 6px; width: 44px; }.character-avatar.body-rising .character-legs i { height: 22px; }.character-avatar.body-rising .character-head { transform: translateY(-2px); }
+.character-avatar.outfit-heavy .character-torso { background: repeating-linear-gradient(105deg,var(--character-color) 0 8px,color-mix(in srgb,var(--character-color),#17201d 20%) 8px 11px); }.character-avatar.outfit-heavy .character-badge { background: rgba(255,237,192,.82); }
+.character-avatar.outfit-near-shore .character-torso { background: linear-gradient(145deg,var(--character-color),#d9f05d); box-shadow: inset 0 -5px rgba(23,32,29,.06),0 0 12px rgba(217,240,93,.5); }.character-avatar.outfit-near-shore .character-badge { color: #51620d; background: #fbffd5; }
+.character-burden { position: absolute; z-index: 1; right: -24px; top: 27px; width: 31px; height: 31px; display: grid; place-items: center; border: 1px solid rgba(23,32,29,.2); border-radius: 10px; background: rgba(255,250,229,.91); box-shadow: 0 7px 12px rgba(23,32,29,.15); font-size: 20px; }
+.character-chains { position: absolute; z-index: 8; inset: 29px -4px -4px; pointer-events: none; }.character-chains i { display: none; position: absolute; width: 15px; height: 9px; border: 3px solid #68716e; border-radius: 50%; box-shadow: inset 0 0 0 1px rgba(255,255,255,.28),0 2px 2px rgba(23,32,29,.2); transform: rotate(-22deg); }.character-chains i:nth-child(1) { left: 5px; top: 10px; }.character-chains i:nth-child(2) { left: 18px; top: 20px; transform: rotate(22deg); }.character-chains i:nth-child(3) { right: 5px; top: 11px; }.character-chains i:nth-child(4) { right: 15px; top: 28px; transform: rotate(24deg); }.chain-level-1 i:nth-child(1),.chain-level-2 i:nth-child(-n+2),.chain-level-3 i:nth-child(-n+3),.chain-level-4 i { display: block; }
+.player-light-ground { z-index: -1; left: 41px; bottom: -6px; width: 105px; transform: translateX(-50%); }.player-light-ground::before { opacity: .24; }
+.player-name { top: 94px; z-index: 12; min-width: 126px; display: grid; grid-template-columns: 1fr auto; gap: 3px 7px; align-items: center; padding: 7px 10px; border-radius: 12px; background: rgba(255,248,232,.97); text-align: left; }
+.player-name span { overflow: hidden; text-overflow: ellipsis; max-width: 110px; }.player-name b { padding: 3px 6px; border-radius: 999px; color: #65750e; background: #edf5ba; font: 900 8px var(--font-mono); }
+
+.world-rules-shade { position: fixed; z-index: 300; inset: 0; display: grid; place-items: center; padding: 22px; overflow: auto; background: radial-gradient(circle at 20% 20%,rgba(126,182,202,.25),transparent 34%),rgba(16,27,24,.91); backdrop-filter: blur(14px); }
+.world-rules-card { width: min(880px,100%); padding: clamp(26px,5vw,48px); border: 1px solid rgba(255,255,255,.2); border-radius: 32px; color: #f6f3e9; background: linear-gradient(145deg,rgba(41,59,52,.98),rgba(22,31,28,.98)); box-shadow: 0 36px 100px rgba(0,0,0,.35); }.world-rules-card > p { margin: 0 0 9px; color: var(--acid); font: 800 11px var(--font-mono); letter-spacing: .14em; }.world-rules-card h2 { max-width: 750px; margin: 0 0 27px; font-size: clamp(28px,5vw,48px); line-height: 1.14; letter-spacing: -.035em; }
+.world-rule-grid { display: grid; grid-template-columns: repeat(2,1fr); gap: 10px; }.world-rule-grid article { display: grid; grid-template-columns: auto 1fr; gap: 4px 12px; padding: 18px; border: 1px solid rgba(255,255,255,.12); border-radius: 18px; background: rgba(255,255,255,.05); }.world-rule-grid b { grid-row: 1/3; color: #8bc4d2; font: 900 18px var(--font-mono); }.world-rule-grid strong { font-size: 15px; }.world-rule-grid span { color: rgba(255,255,255,.64); font-size: 13px; line-height: 1.6; }
+.world-rules-card > button { width: 100%; min-height: 56px; margin-top: 18px; border: 0; border-radius: 16px; color: #17201d; background: var(--acid); font-size: 16px; font-weight: 900; cursor: pointer; }.world-rules-card > small { display: block; margin-top: 12px; color: rgba(255,255,255,.55); text-align: center; }
+
+.identity-form fieldset,.diy-situation > label:not(.pressure-box) { border: 1px solid rgba(23,32,29,.14); border-radius: 15px; padding: 13px; }.identity-form fieldset legend { padding: 0 7px; color: #51706a; font-size: 12px; font-weight: 900; }.identity-form fieldset small { display: block; color: #74847e; line-height: 1.55; }.diy-situation { display: grid; gap: 12px; }.diy-situation textarea { min-height: 74px; }
+.personal-profile-panel { margin: 18px 0; padding: 20px; border: 1px solid rgba(126,182,202,.32); border-radius: 20px; background: linear-gradient(145deg,rgba(235,248,244,.9),rgba(250,247,228,.9)); }.profile-trait-pills { display: flex; flex-wrap: wrap; gap: 7px; margin: 14px 0; }.profile-trait-pills span { padding: 7px 10px; border-radius: 999px; color: #3e615e; background: #fff; box-shadow: 0 4px 11px rgba(38,76,70,.07); font-size: 12px; font-weight: 800; }.personal-profile-panel details { margin-top: 12px; }.personal-profile-panel summary { padding: 11px 13px; border-radius: 12px; color: #2e6863; background: #dceee7; font-weight: 900; cursor: pointer; }.personal-profile-form { display: grid; gap: 12px; margin-top: 13px; }.personal-profile-form label { display: grid; gap: 6px; color: #44645f; font-size: 12px; font-weight: 800; }.personal-profile-form input,.personal-profile-form select,.personal-profile-form textarea { width: 100%; border: 1px solid #c9d9d3; border-radius: 11px; padding: 10px; background: #fff; font: inherit; }.personal-profile-form textarea { min-height: 76px; resize: vertical; }.personal-profile-form > button { min-height: 46px; border: 0; border-radius: 12px; color: #fff; background: #31776f; font-weight: 900; cursor: pointer; }.personal-profile-panel > p { margin: 13px 0 0; color: #69807b; font-size: 12px; line-height: 1.65; }
+.self-portrait { display: grid; place-items: center; }.self-portrait > span { margin-top: 8px; padding: 5px 8px; border-radius: 999px; color: #5d6f10; background: #eff6bf; font: 900 9px var(--font-mono); }.interest-estimate-note { margin: 0 0 15px; padding: 11px 13px; border-radius: 12px; color: #745f3b; background: #fff5d9; font-size: 11px; line-height: 1.6; }
+.mbti-insight-panel { margin-top: 18px; padding: 20px; border: 1px solid rgba(126,182,202,.35); border-radius: 19px; background: #f4f7f2; }.mbti-insight-panel > header { display: flex; justify-content: space-between; gap: 16px; align-items: flex-end; }.mbti-insight-panel header p { margin: 0; color: #6b8984; font: 800 9px var(--font-mono); letter-spacing: .12em; }.mbti-insight-panel h3 { margin: 5px 0 0; }.mbti-insight-panel header > strong { color: #3e716d; font: 900 15px var(--font-mono); }.insight-lock.compact { margin-top: 14px; padding: 16px; }.mbti-aggregate-list { display: grid; gap: 8px; margin-top: 16px; }.mbti-aggregate-list > div { display: grid; grid-template-columns: 24px 48px 1fr auto auto; gap: 9px; align-items: center; }.mbti-aggregate-list b { color: #8aa09b; }.mbti-aggregate-list i { height: 9px; overflow: hidden; border-radius: 999px; background: #dde6e1; }.mbti-aggregate-list i span { display: block; height: 100%; border-radius: inherit; background: linear-gradient(90deg,#7eb6ca,#d9f05d); }.mbti-aggregate-list em { color: #446761; font-size: 11px; font-style: normal; font-weight: 900; }.mbti-aggregate-list small { color: #849591; }.mbti-insight-panel > p { margin: 15px 0 0; color: #7a8d88; font-size: 11px; line-height: 1.55; }
+
+.modal-shade .modal-close,.country-gate .modal-close { position: sticky; z-index: 120; top: 14px; right: auto; float: right; margin: 14px 14px -48px auto; display: grid; place-items: center; color: var(--ink); background: rgba(250,248,240,.94); box-shadow: 0 8px 20px rgba(23,32,29,.18); backdrop-filter: blur(9px); }.guide-header { position: sticky; z-index: 30; top: 0; }
+
+@media (max-width: 760px) { .kian-pet-button { min-width: 48px !important; grid-template-columns: 40px !important; padding: 4px !important; }.kian-pet-button b,.kian-pet-button small { display: none; }.kian-pet-button .golden-dog { width: 40px; height: 36px; }.world-rule-grid { grid-template-columns: 1fr; }.world-canvas { left: -42%; top: -25%; width: 184%; height: 150%; }.world-zoom-controls { right: 8px; bottom: 72px; }.player-name { min-width: 112px; }.mbti-aggregate-list > div { grid-template-columns: 20px 42px 1fr auto; }.mbti-aggregate-list small { display: none; } }
+
+* { box-sizing: border-box; }
+html, body { margin: 0; min-height: 100%; background: #161c1a; font-family: var(--font-ui); color: var(--ink); line-height: 1.5; }
+button, input, textarea, select { font: inherit; }
+button, a { -webkit-tap-highlight-color: transparent; }
+button { color: inherit; }
+a { color: inherit; text-decoration: none; }
+
+.game-shell { height: 100vh; min-height: 680px; display: flex; flex-direction: column; background: #171d1b; color: var(--paper); overflow: hidden; position: relative; }
+.game-topbar {
+ min-height: 72px; height: auto; flex: 0 0 auto; display: grid;
+ grid-template-columns: minmax(190px,.8fr) auto minmax(0,2.2fr); grid-template-areas: "brand date actions";
+ align-items: center; gap: 10px 16px;
+ padding: 10px 18px; border-bottom: 1px solid rgba(255,255,255,.11); background: #151b19;
+ position: relative; z-index: 20;
+}
+.game-brand { grid-area: brand; min-width: 0; display: flex; align-items: center; gap: 11px; }
+.game-brand > div { display: flex; flex-direction: column; gap: 3px; }
+.game-brand strong { font-weight: 900; letter-spacing: .08em; font-size: 15px; }
+.game-brand small { color: rgba(243,240,230,.55); font: 600 11px var(--font-mono); letter-spacing: .11em; }
+.planet-mark { width: 39px; height: 39px; display: grid; place-items: center; border: 1px solid var(--acid); border-radius: 50%; color: var(--acid); font-size: 22px; }
+.world-date { grid-area: date; font: 600 11px var(--font-mono); letter-spacing: .08em; color: rgba(243,240,230,.68); display: flex; align-items: center; gap: 9px; }
+.live-dot { width: 7px; height: 7px; border-radius: 50%; background: var(--acid); box-shadow: 0 0 0 5px rgba(217,240,93,.12); }
+.top-actions { grid-area: actions; min-width: 0; justify-self: stretch; display: flex; flex-wrap: wrap; justify-content: flex-end; align-items: center; gap: 8px; }
+.top-actions > button, .top-actions > a, .top-actions > .vault-status { min-height: 38px; display: inline-flex; align-items: center; justify-content: center; border: 1px solid rgba(255,255,255,.19); background: transparent; color: var(--paper); border-radius: 999px; padding: 9px 13px; font-size: 12px; line-height: 1.2; white-space: nowrap; cursor: pointer; }
+.top-actions > button { background: var(--acid); color: var(--ink); border-color: var(--acid); font-weight: 800; }
+.save-state { color: rgba(243,240,230,.52); font-size: 11px; }
+.top-actions > .vault-status { display: inline-flex; align-items: center; border: 1px solid rgba(255,255,255,.18); border-radius: 999px; background: transparent; color: rgba(243,240,230,.68); padding: 10px 15px; font-size: 12px; font-weight: 700; }
+.top-actions > .vault-status.vault-synced { color: var(--acid); border-color: rgba(217,240,93,.58); }
+.top-actions > .vault-status.vault-error { color: #ff9a7e; border-color: rgba(232,110,78,.65); }
+.top-actions > .admin-open { background: rgba(122,176,198,.18); color: #dff7ff; border-color: rgba(122,176,198,.48); }
+.top-actions > .feedback-open { background: rgba(255,255,255,.08); color: #fff; border-color: rgba(255,255,255,.28); }
+.top-actions > .invite-open { background: linear-gradient(135deg,#f6e28a,#d9f05d); color: #183a37; border-color: #f7eead; box-shadow: 0 0 0 2px rgba(217,240,93,.12),0 7px 20px rgba(217,240,93,.17); }
+.top-actions > .beta-admin-open { color: var(--acid); border-color: rgba(217,240,93,.48); }
+.top-actions > .vault-status.vault-syncing,
+.top-actions > .vault-status.vault-checking { opacity: .7; }
+.top-actions > .vault-status { cursor: default; }
+
+.game-layout { flex: 1 1 auto; min-height: 0; display: grid; grid-template-columns: 320px minmax(0, 1fr); height: auto; }
+.debt-hud { background: #202724; border-right: 1px solid rgba(255,255,255,.1); padding: 26px 20px; overflow-y: auto; position: relative; z-index: 12; }
+.hud-kicker { color: var(--acid); font: 700 11px var(--font-mono); letter-spacing: .13em; margin: 0 0 24px; }
+.hud-total { padding-bottom: 23px; border-bottom: 1px solid rgba(255,255,255,.11); display: flex; flex-direction: column; }
+.hud-total small, .hud-metrics small { color: rgba(243,240,230,.55); font-size: 11px; }
+.hud-total strong { font: 700 31px/1.1 var(--font-mono); margin: 8px 0; letter-spacing: -.04em; }
+.hud-total > span { font-size: 11px; color: rgba(243,240,230,.62); }
+.hud-metrics { display: grid; grid-template-columns: 1fr 1fr; gap: 8px; padding: 17px 0; border-bottom: 1px solid rgba(255,255,255,.11); }
+.hud-metrics div { display: flex; flex-direction: column; gap: 6px; }
+.hud-metrics strong { font: 700 14px var(--font-mono); }
+.hud-focus-card, .hud-cashflow { width: 100%; border: 1px solid rgba(255,255,255,.13); color: var(--paper); text-align: left; padding: 13px; cursor: pointer; display: flex; flex-direction: column; gap: 5px; }
+.hud-focus-card { margin-top: 16px; background: linear-gradient(135deg, rgba(217,240,93,.16), rgba(255,255,255,.025)); border-color: rgba(217,240,93,.55); box-shadow: 3px 3px 0 rgba(217,240,93,.15); }
+.hud-cashflow { margin-top: 8px; background: rgba(126,182,202,.1); }
+.hud-focus-card:hover, .hud-cashflow:hover { border-color: var(--acid); transform: translateY(-1px); }
+.hud-focus-card > span, .hud-cashflow > span { color: rgba(243,240,230,.58); font: 700 10px var(--font-mono); letter-spacing: .08em; }
+.hud-focus-card strong { color: var(--acid); font-size: 16px; }
+.hud-focus-card em { color: rgba(243,240,230,.78); font: 700 11px var(--font-mono); font-style: normal; }
+.hud-cashflow strong { font: 800 18px var(--font-mono); color: #a7d9e9; }
+.hud-cashflow small { color: rgba(243,240,230,.6); font-size: 10px; line-height: 1.55; }
+.hud-cashflow.cashflow-negative strong { color: #ff9a7e; }
+.debt-stack { display: flex; flex-direction: column; gap: 7px; padding: 16px 0; }
+.debt-mini-card { border: 1px solid rgba(255,255,255,.1); background: rgba(255,255,255,.035); color: var(--paper); padding: 12px; display: grid; grid-template-columns: 9px 1fr auto; align-items: center; gap: 10px; text-align: left; cursor: pointer; border-radius: 4px; }
+.debt-mini-card:hover { background: rgba(255,255,255,.08); border-color: var(--acid); }
+.debt-mini-card > div { min-width: 0; display: flex; flex-direction: column; gap: 3px; }
+.debt-mini-card strong { font-size: 13px; }
+.debt-mini-card strong b { display: inline-block; margin-left: 4px; padding: 2px 4px; background: var(--acid); color: var(--ink); font: 800 8px var(--font-mono); }
+.debt-mini-card small { color: rgba(243,240,230,.58); font: 500 11px var(--font-mono); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
+.debt-mini-card i { font: 700 11px var(--font-mono); color: var(--acid); font-style: normal; }
+.debt-mini-card.debt-mini-primary { border-color: rgba(217,240,93,.58); background: rgba(217,240,93,.08); }
+.kind-dot { width: 8px; height: 8px; border-radius: 50%; display: inline-block; flex: 0 0 auto; }
+.kind-mortgage { background: #7eb6ca; } .kind-card { background: #e86e4e; } .kind-education { background: #bba7db; } .kind-medical { background: #efb274; } .kind-car { background: #81c49a; } .kind-personal { background: #edcc6c; } .kind-business { background: #ca887e; } .kind-bnpl { background: #77c4c1; } .kind-informal { background: #d09cc6; } .kind-other { background: #9aa49e; }
+.empty-debts { font-size: 12px; line-height: 1.7; color: rgba(243,240,230,.56); border: 1px dashed rgba(255,255,255,.15); padding: 15px; margin: 0; }
+.add-debt-button { width: 100%; border: 1px solid var(--acid); background: transparent; color: var(--acid); padding: 12px; cursor: pointer; font-size: 12px; font-weight: 700; }
+.add-debt-button:hover { background: var(--acid); color: var(--ink); }
+.add-debt-note { display: block; margin: 8px 0 0; color: rgba(243,240,230,.52); font-size: 10px; line-height: 1.55; }
+.hud-tip { display: flex; gap: 10px; border-top: 1px solid rgba(255,255,255,.1); margin-top: 20px; padding-top: 18px; }
+.hud-tip > span { width: 30px; height: 30px; display: grid; place-items: center; border: 1px solid rgba(255,255,255,.2); border-radius: 3px; }
+.hud-tip p { margin: 0; display: flex; flex-direction: column; gap: 5px; color: rgba(243,240,230,.55); font-size: 11px; line-height: 1.55; }
+.hud-tip strong { color: rgba(243,240,230,.82); font-size: 12px; }
+
+.world-wrap { display: grid; grid-template-rows: minmax(0,1fr) 112px; min-width: 0; background: #cbc7ba; }
+.world-stage {
+ position: relative; overflow: hidden; min-height: 570px;
+ background:
+ radial-gradient(circle at 74% 28%, rgba(217,240,93,.21), transparent 20%),
+ radial-gradient(circle at 22% 72%, rgba(126,182,202,.25), transparent 24%),
+ linear-gradient(140deg, #e6e1d2, #cfcabd);
+}
+.world-noise { position: absolute; inset: 0; opacity: .17; background-image: radial-gradient(rgba(23,32,29,.5) .8px, transparent .8px); background-size: 9px 9px; mask-image: linear-gradient(to bottom, #000, transparent 80%); }
+.world-stage::before, .world-stage::after { content: ""; position: absolute; border: 1px solid rgba(23,32,29,.16); border-radius: 50%; }
+.world-stage::before { width: 72%; height: 72%; left: 14%; top: 11%; }
+.world-stage::after { width: 48%; height: 103%; left: 25%; top: -2%; border-style: dashed; }
+.road { position: absolute; background: rgba(247,245,236,.66); border: 1px solid rgba(23,32,29,.12); box-shadow: inset 0 0 0 5px rgba(255,255,255,.22); }
+.road::after { content:""; position:absolute; inset:50% 4% auto; border-top:1px dashed rgba(23,32,29,.23); }
+.road-a { width: 116%; height: 55px; left: -8%; top: 51%; transform: rotate(-7deg); }
+.road-b { width: 52px; height: 115%; top: -8%; left: 48%; transform: rotate(16deg); }
+.road-b::after { inset:4% auto 4% 50%; border-top:0; border-left:1px dashed rgba(23,32,29,.23); }
+.road-c { width: 62%; height: 43px; right: -5%; top: 25%; transform: rotate(13deg); }
+.district { position: absolute; width: 110px; height: 76px; border: 1px solid rgba(23,32,29,.18); background: rgba(247,245,236,.42); backdrop-filter: blur(3px); display: flex; flex-direction: column; align-items: center; justify-content: center; gap: 8px; color: rgba(23,32,29,.56); }
+.district span { font-size: 21px; }
+.district strong { font: 700 10px var(--font-mono); letter-spacing: .06em; text-align: center; }
+.district small { min-width: 28px; border-radius: 999px; background: rgba(23,32,29,.1); padding: 2px 7px; font: 900 8px var(--font-mono); }
+.district[class*="growth-tier-"]:not(.growth-tier-0) { border-color: rgba(115,138,20,.38); box-shadow: 0 8px 24px rgba(115,138,20,.12); }
+.growth-tier-3, .growth-tier-4, .growth-tier-5 { background: rgba(248,255,201,.72); }
+.district-home { left: 7%; top: 9%; transform: rotate(-3deg); }
+.district-card { right: 8%; top: 7%; transform: rotate(2deg); }
+.district-study { left: 10%; bottom: 7%; }
+.district-calm { right: 9%; bottom: 6%; transform: rotate(-2deg); }
+.district-real { left: 47%; top: 5%; transform: rotate(-1deg); color: #51620d; background: rgba(251,255,218,.82); }
+.world-growth-status { position: absolute; z-index: 18; left: 50%; top: 13px; transform: translateX(-50%); max-width: calc(100% - 520px); border: 1px solid rgba(255,255,255,.2); border-radius: 999px; background: rgba(23,32,29,.92); color: #fff; padding: 8px 14px; display: flex; align-items: center; gap: 10px; box-shadow: 0 10px 28px rgba(23,32,29,.2); backdrop-filter: blur(8px); pointer-events: none; white-space: nowrap; }
+.world-growth-status b { color: var(--acid); font: 900 9px var(--font-mono); letter-spacing: .06em; }
+.world-growth-status span { font-size: 10px; font-weight: 800; color: rgba(255,255,255,.74); }
+
+.npc { position: absolute; transform: translate(-50%,-50%); border: 0; background: transparent; display: flex; flex-direction: column; align-items: center; cursor: pointer; z-index: 5; color: var(--ink); transition: transform .18s; }
+.npc:hover, .npc-near { transform: translate(-50%,-56%); }
+.npc-tag { position: relative; min-width: 154px; background: linear-gradient(145deg, rgba(31,42,38,.97), rgba(20,28,25,.95)); color: #fff; padding: 11px 13px; border: 1px solid rgba(255,255,255,.17); border-radius: 17px; box-shadow: 0 12px 28px rgba(23,32,29,.22), 0 0 0 4px rgba(122,176,198,.06); backdrop-filter: blur(8px); margin-bottom: 9px; white-space: nowrap; display: grid; grid-template-columns: 1fr auto; gap: 3px 8px; text-align: left; transition: transform .18s ease, box-shadow .18s ease; }
+.npc-tag::before { content: ""; position: absolute; left: 16px; right: 16px; top: 0; height: 2px; border-radius: 999px; background: linear-gradient(90deg, transparent, rgba(122,176,198,.8), transparent); }
+.npc-tag::after { content: ""; position: absolute; left: 50%; bottom: -5px; width: 10px; height: 10px; transform: translateX(-50%) rotate(45deg); border-radius: 2px; background: #18211e; }
+.npc:hover .npc-tag, .npc-near .npc-tag { transform: translateY(-2px); box-shadow: 0 16px 34px rgba(23,32,29,.27), 0 0 0 5px rgba(122,176,198,.09); }
+.community-npc { z-index: 7; }
+.community-npc .real-story-tag { border-color: rgba(217,240,93,.55); box-shadow: 0 13px 30px rgba(23,32,29,.24), 0 0 0 5px rgba(217,240,93,.09); }
+.community-npc .real-story-tag::before { background: linear-gradient(90deg, transparent, rgba(217,240,93,.96), transparent); }
+.community-npc .real-story-tag .npc-tag-label { color: var(--acid); }
+.community-npc .npc-name { background: rgba(249,255,216,.92); border-color: rgba(151,174,45,.22); }
+.npc-light-ground { position: absolute; z-index: 0; left: 50%; bottom: 25px; width: 92px; height: 42px; transform: translateX(-50%); pointer-events: none; }
+.npc-light-ground::before { content: ""; position: absolute; inset: 9px 4px 0; border-radius: 50%; background: radial-gradient(ellipse, rgba(255,245,155,.82), rgba(217,240,93,.38) 42%, transparent 72%); filter: blur(3px); opacity: .34; }
+.npc-light-ground::after { content: ""; position: absolute; left: 50%; bottom: 1px; width: 62px; height: 23px; transform: translateX(-50%); border-radius: 50%; border: 1px solid rgba(255,242,133,.28); opacity: 0; }
+.npc-light-ground i { position: absolute; width: 5px; height: 5px; border-radius: 50%; background: #fffbd0; box-shadow: 0 0 8px #f7ff8b, 0 0 13px rgba(217,240,93,.7); opacity: 0; }
+.npc-light-ground i:nth-child(1) { left: 17px; top: 17px; }
+.npc-light-ground i:nth-child(2) { right: 17px; top: 12px; animation-delay: -.5s; }
+.npc-light-ground i:nth-child(3) { left: 31px; top: 2px; animation-delay: -.9s; }
+.npc-light-ground i:nth-child(4) { right: 31px; top: 0; animation-delay: -.2s; }
+.npc-light-ground i:nth-child(5) { left: 8px; top: 5px; animation-delay: -1.3s; }
+.npc-light-ground i:nth-child(6) { right: 8px; top: 22px; animation-delay: -.7s; }
+.light-tier-1::before { opacity: .38; }
+.light-tier-1 i:nth-child(-n+2) { opacity: .72; animation: light-twinkle 1.9s ease-in-out infinite; }
+.light-tier-2::before { opacity: .56; transform: scale(1.07); }
+.light-tier-2::after { opacity: .42; }
+.light-tier-2 i:nth-child(-n+4) { opacity: .82; animation: light-twinkle 1.9s ease-in-out infinite; }
+.light-tier-3::before { opacity: .76; transform: scale(1.16); }
+.light-tier-3::after { opacity: .68; box-shadow: 0 0 14px rgba(217,240,93,.52); animation: light-ring 2.5s ease-in-out infinite; }
+.light-tier-3 i { opacity: .9; animation: light-twinkle 1.65s ease-in-out infinite; }
+.light-tier-4::before { opacity: .96; transform: scale(1.28); background: radial-gradient(ellipse, rgba(255,251,193,.94), rgba(217,240,93,.54) 38%, rgba(122,176,198,.2) 59%, transparent 76%); }
+.light-tier-4::after { opacity: .9; width: 79px; height: 30px; box-shadow: 0 0 18px rgba(217,240,93,.7), inset 0 0 12px rgba(122,176,198,.4); animation: light-ring 2s ease-in-out infinite; }
+.light-tier-4 i { width: 6px; height: 6px; opacity: 1; animation: light-twinkle 1.35s ease-in-out infinite; }
+.burden-lift { position: absolute; z-index: 7; left: 50%; bottom: 43px; width: 104px; height: 108px; transform: translateX(-50%); pointer-events: none; }
+.burden-lift > i { position: absolute; display: none; width: 24px; height: 30px; border: 1px solid rgba(53,76,83,.3); border-radius: 52% 52% 48% 48%; background: linear-gradient(145deg, rgba(255,255,255,.96), rgba(126,182,202,.9)); box-shadow: inset -5px -6px 8px rgba(54,107,126,.14), 0 5px 13px rgba(52,91,104,.18); transform-origin: 50% 110%; animation: burden-balloon-float 2.8s ease-in-out infinite; }
+.burden-lift > i::after { content: ""; position: absolute; left: 50%; bottom: -4px; width: 6px; height: 6px; transform: translateX(-50%) rotate(45deg); background: #88bfd1; border-right: 1px solid rgba(53,76,83,.28); border-bottom: 1px solid rgba(53,76,83,.28); }
+.burden-lift > i:nth-child(1) { display: block; right: 4px; top: 25px; }
+.burden-lift > i:nth-child(2) { right: 27px; top: 9px; background: linear-gradient(145deg, #fff7b1, #d9f05d); animation-delay: -.8s; }
+.burden-lift > i:nth-child(3) { right: 1px; top: -6px; width: 29px; height: 36px; background: linear-gradient(145deg, #ffe9c2, #ef9b6e); animation-delay: -1.5s; }
+.burden-lift > i:nth-child(4) { right: 31px; top: -18px; width: 32px; height: 40px; background: linear-gradient(145deg, #eee8ff, #b9a7db); animation-delay: -.35s; }
+.burden-lift > b { position: absolute; display: none; right: -2px; top: 7px; width: 62px; height: 23px; border-radius: 999px; background: rgba(255,255,255,.86); box-shadow: -19px 4px 0 -4px rgba(255,255,255,.8), 16px 5px 0 -6px rgba(255,255,255,.82), 0 6px 15px rgba(60,91,104,.15); animation: burden-cloud-float 3.4s ease-in-out infinite; }
+.burden-lift > span { position: absolute; right: 17px; top: 52px; width: 1px; height: 45px; background: linear-gradient(rgba(67,92,100,.64), rgba(67,92,100,.15)); transform: rotate(12deg); transform-origin: top; }
+.burden-lift > span::after { content: ""; position: absolute; left: -20px; bottom: -2px; width: 25px; height: 1px; background: rgba(67,92,100,.44); transform: rotate(-17deg); transform-origin: right; }
+.lift-tier-2 > i:nth-child(2), .lift-tier-3 > i:nth-child(-n+3), .lift-tier-4 > i { display: block; }
+.lift-tier-2 > span { height: 48px; }.lift-tier-3 > span { height: 52px; }.lift-tier-4 > span { height: 56px; }
+.lift-tier-3 > b, .lift-tier-4 > b { display: block; }
+.lift-tier-4 { transform: translateX(-50%) scale(1.08); }
+.npc-light-burst .burden-lift { animation: burden-lift-arrival .95s ease-out; }
+.npc-light-burst .npc-light-ground { animation: light-arrival .9s ease-out; }
+.npc-light-burst .npc-character { animation: light-character-bounce .65s ease-out; }
+.npc-tag-label { grid-column: 1/-1; color: rgba(255,255,255,.62); font: 700 9px var(--font-mono); letter-spacing: .1em; }
+.npc-tag strong { grid-column: 1/-1; font: 900 14px var(--font-mono); }
+.npc-tag b { color: var(--acid); font: 800 10px var(--font-mono); }
+.npc-tag i { color: #a7d9e9; font: 800 10px var(--font-mono); font-style: normal; text-align: right; }
+.npc-tag i.negative { color: #ff9a7e; }
+.npc small { background: rgba(250,248,240,.88); border: 1px solid rgba(23,32,29,.1); border-radius: 999px; padding: 4px 9px; box-shadow: 0 4px 10px rgba(23,32,29,.1); font-size: 10px; font-weight: 700; margin-top: 5px; }
+.npc-name { display: flex; align-items: center; gap: 6px; }
+.npc-name b { color: #7b8b20; font: 900 10px var(--font-mono); }
+.npc em { position: absolute; top: 48%; left: 52px; background: rgba(217,240,93,.96); border: 1px solid rgba(23,32,29,.18); border-radius: 999px; box-shadow: 0 7px 16px rgba(23,32,29,.16); padding: 6px 9px; font: 700 10px var(--font-mono); font-style: normal; white-space: nowrap; }
+
+.character-avatar { position: relative; display: block; width: 56px; height: 78px; filter: drop-shadow(0 5px 2px rgba(23,32,29,.16)); }
+.character-avatar i { display: block; font-style: normal; }
+.character-head { position: absolute; z-index: 4; width: 38px; height: 39px; left: 9px; top: 0; border: 1.5px solid rgba(23,32,29,.34); border-radius: 46% 46% 48% 48%; background: var(--character-skin); box-shadow: inset 0 -3px rgba(91,48,32,.08), 0 2px 5px rgba(23,32,29,.08); }
+.character-ear { position: absolute; z-index: -1; width: 8px; height: 12px; top: 14px; border: 1.5px solid rgba(23,32,29,.3); border-radius: 50%; background: var(--character-skin); }
+.ear-left { left: -6px; } .ear-right { right: -6px; }
+.character-hair { position: absolute; left: -1px; top: -3px; width: 40px; height: 17px; border: 1.5px solid rgba(23,32,29,.38); border-bottom: 0; border-radius: 55% 55% 28% 22%; background: var(--character-hair); }
+.character-fringe { position: absolute; left: 1px; top: 7px; width: 16px; height: 10px; border-radius: 0 0 80% 12%; background: var(--character-hair); transform: rotate(-9deg); }
+.character-eyes { position: absolute; left: 8px; top: 18px; width: 22px; display: flex; justify-content: space-between; }
+.character-eyes i { width: 5px; height: 6px; border-radius: 50%; background: var(--ink); box-shadow: inset 1px 1px rgba(255,255,255,.72); }
+.character-cheek { position: absolute; top: 27px; width: 6px; height: 3px; border-radius: 50%; background: rgba(220,91,80,.36); }
+.cheek-left { left: 5px; } .cheek-right { right: 5px; }
+.character-smile { position: absolute; left: 15px; top: 27px; width: 8px; height: 5px; border-bottom: 2px solid rgba(67,35,27,.8); border-radius: 50%; }
+.character-torso { position: absolute; z-index: 3; left: 5px; top: 33px; width: 46px; height: 35px; border: 1.5px solid rgba(23,32,29,.34); border-radius: 48% 48% 22% 22%; background: var(--character-color); box-shadow: inset 0 -5px rgba(23,32,29,.08), 0 3px 6px rgba(23,32,29,.08); }
+.character-badge { position: absolute; left: 50%; top: 10px; transform: translateX(-50%); min-width: 20px; height: 17px; display: grid !important; place-items: center; border-radius: 9px; background: rgba(255,255,255,.7); font-size: 10px; line-height: 1; }
+.character-arm { position: absolute; top: 8px; width: 11px; height: 28px; border: 1.5px solid rgba(23,32,29,.32); border-radius: 9px; background: var(--character-color); transform-origin: top center; }
+.arm-left { left: -7px; transform: rotate(13deg); } .arm-right { right: -7px; transform: rotate(-13deg); }
+.character-legs { position: absolute; z-index: 2; left: 13px; bottom: 0; width: 30px; display: flex; justify-content: space-between; }
+.character-legs i { width: 12px; height: 18px; border: 1.5px solid rgba(23,32,29,.34); border-radius: 3px 3px 7px 7px; background: #34443e; }
+.npc-character { z-index: 1; margin: 0 auto; transition: transform .18s ease; }
+.npc:hover .npc-character, .npc-near .npc-character { transform: translateY(-3px); }
+
+.player { position: absolute; width: 82px; height: 108px; transform: translate(-50%,-50%); z-index: 10; transition: left .11s linear, top .11s linear; }
+.player::before { content: ""; position: absolute; z-index: -2; left: -15px; top: -13px; width: 112px; height: 112px; border-radius: 50%; background: radial-gradient(circle, rgba(232,110,78,.16) 0 40%, rgba(217,240,93,.12) 41% 55%, transparent 72%); box-shadow: 0 0 34px rgba(232,110,78,.18); animation: self-aura 2.8s ease-in-out infinite; }
+.player-shadow { position: absolute; width: 68px; height: 19px; border-radius: 50%; background: radial-gradient(ellipse, rgba(232,110,78,.4), rgba(217,240,93,.2) 52%, transparent 74%); left: 7px; bottom: -1px; filter: blur(1px); }
+.player-avatar { width: 70px; height: 92px; position: absolute; z-index: 6; left: 6px; top: 0; transform-origin: bottom center; border: 0; background: transparent; padding: 0; cursor: pointer; }
+.player-character { transform: scale(1.24); transform-origin: top center; margin: 0 auto; filter: drop-shadow(0 6px 5px rgba(232,110,78,.24)); }
+.facing-left .player-avatar { transform: rotate(-4deg); } .facing-right .player-avatar { transform: rotate(4deg); }
+.facing-left .character-eyes { transform: translateX(-2px); } .facing-right .character-eyes { transform: translateX(2px); }
+.facing-up .character-smile { opacity: .35; }
+.player-self-marker { position: absolute; z-index: 8; left: 76px; top: 62px; border-radius: 999px; background: linear-gradient(90deg, var(--coral), #f39167); color: #fff; padding: 5px 9px; box-shadow: 0 6px 14px rgba(232,110,78,.26); font: 900 10px var(--font-mono); letter-spacing: .04em; white-space: nowrap; pointer-events: none; }
+.player-name { position: absolute; z-index: 7; top: 93px; left: 50%; transform: translateX(-50%); background: rgba(255,244,229,.92); border: 1px solid rgba(232,110,78,.2); border-radius: 999px; padding: 5px 10px; font-size: 10px; font-weight: 900; white-space: nowrap; box-shadow: 0 6px 13px rgba(232,110,78,.15); backdrop-filter: blur(5px); }
+.player-total-debt { position: absolute; left: 50%; top: -109px; transform: translateX(-50%); min-width: 232px; background: linear-gradient(145deg, rgba(42,38,31,.98), rgba(20,27,24,.97)); color: #fff; border: 1px solid rgba(255,255,255,.2); border-radius: 19px; padding: 12px 14px; box-shadow: 0 17px 38px rgba(23,32,29,.27), 0 0 0 5px rgba(232,110,78,.07); text-align: center; z-index: 5; white-space: nowrap; cursor: pointer; transition: transform .18s ease, box-shadow .18s ease; }
+.player-total-debt:hover { transform: translateX(-50%) translateY(-3px); box-shadow: 0 21px 43px rgba(23,32,29,.32), 0 0 0 6px rgba(232,110,78,.11); }
+.player-total-debt::before { content: ""; position: absolute; left: 22px; right: 22px; top: 0; height: 2px; border-radius: 999px; background: linear-gradient(90deg, transparent, rgba(232,110,78,.85), rgba(217,240,93,.8), transparent); }
+.player-total-debt::after { content: ""; position: absolute; left: 50%; bottom: -6px; width: 12px; height: 12px; transform: translateX(-50%) rotate(45deg); background: #161e1b; border-radius: 3px; }
+.player-total-debt small { display: block; color: rgba(255,255,255,.68); font: 700 10px var(--font-mono); letter-spacing: .09em; }
+.player-total-debt strong { display: block; margin: 2px 0 5px; font: 900 20px var(--font-mono); letter-spacing: -.04em; }
+.player-total-debt > span, .player-total-debt > i { display: inline-block; padding: 3px 5px; font: 800 10px var(--font-mono); font-style: normal; }
+.player-total-debt > span { background: var(--acid); color: var(--ink); border-radius: 999px; }
+.player-total-debt > i { margin-left: 4px; background: rgba(126,182,202,.22); color: #b8e3f1; border-radius: 999px; }
+.player-total-debt > i.negative { background: rgba(232,110,78,.25); color: #ffb39f; }
+.orbit-label {
+ position: absolute; left: 50%; top: 42%; transform: translate(calc(-50% + var(--orbit-x)), calc(-50% + var(--orbit-y)));
+ min-width: 124px; border: 1px solid rgba(23,32,29,.18); border-radius: 14px; background: rgba(248,246,238,.94); color: var(--ink); padding: 9px 11px; cursor: pointer; box-shadow: 0 9px 22px rgba(23,32,29,.14), inset 0 1px rgba(255,255,255,.8); backdrop-filter: blur(7px); display: grid; grid-template-columns: 1fr auto; gap: 3px 7px; z-index: 2; transition: box-shadow .18s ease, filter .18s ease;
+}
+.orbit-label:hover { z-index: 4; filter: brightness(1.03); box-shadow: 0 13px 28px rgba(23,32,29,.2), 0 0 0 4px rgba(255,255,255,.25); }
+.orbit-label::after { display: none; }
+.orbit-label span { font-size: 10px; color: var(--muted); grid-column: 1/-1; text-align: left; }
+.orbit-label strong { font: 700 11px var(--font-mono); }
+.orbit-label i { width: 21px; height: 21px; display: grid; place-items: center; border-radius: 50%; font: 700 7px var(--font-mono); font-style: normal; background: conic-gradient(var(--acid) var(--debt-progress), #ddd8ca 0); box-shadow: inset 0 0 0 2px rgba(255,255,255,.58); }
+.orbit-label.orbit-primary { border-color: rgba(232,110,78,.46); background: linear-gradient(145deg, rgba(255,247,216,.97), rgba(248,234,201,.94)); box-shadow: 0 12px 27px rgba(123,69,41,.16), 0 0 0 4px rgba(232,110,78,.09); }
+.orbit-label.orbit-primary span { color: #5a660f; font-weight: 900; }
+.orbit-more-label { position: absolute; z-index: 3; left: calc(50% + 150px); top: calc(42% + 198px); transform: translateX(-50%); min-width: 124px; border: 1px dashed rgba(23,32,29,.24); border-radius: 999px; background: rgba(250,248,240,.9); color: var(--muted); padding: 8px 11px; box-shadow: 0 7px 17px rgba(23,32,29,.1); font: 800 10px var(--font-mono); cursor: pointer; white-space: nowrap; }
+.proximity-line { position: absolute; width: 90px; height: 2px; border: 0; background: linear-gradient(90deg, rgba(232,110,78,.48), transparent); left: 50%; top: 50%; z-index: -1; filter: blur(.2px); }
+.world-message { position: absolute; left: 27px; top: 24px; max-width: 280px; display: flex; gap: 10px; color: rgba(23,32,29,.6); }
+.world-message span { font: 700 31px Georgia, serif; color: var(--coral); }
+.world-message p { margin: 8px 0 0; font-size: 13px; line-height: 1.6; font-weight: 700; }
+.light-feedback-toast { position: absolute; z-index: 30; left: 50%; bottom: 132px; transform: translateX(-50%); display: flex; align-items: center; gap: 10px; min-width: 230px; border: 1px solid rgba(255,255,255,.46); border-radius: 999px; background: rgba(24,34,30,.94); color: #fff; padding: 10px 15px 10px 10px; box-shadow: 0 14px 34px rgba(23,32,29,.3), 0 0 26px rgba(217,240,93,.25); backdrop-filter: blur(9px); animation: light-toast 1.5s ease both; }
+.light-feedback-toast b { width: 39px; height: 39px; display: grid; place-items: center; border-radius: 50%; background: var(--acid); color: var(--ink); font: 900 13px var(--font-mono); box-shadow: 0 0 18px rgba(217,240,93,.55); }
+.light-feedback-toast span { font-size: 14px; font-weight: 900; }
+.real-light-toast { box-shadow: 0 14px 34px rgba(23,32,29,.3), 0 0 32px rgba(217,240,93,.4); }
+.real-world-empty { position: absolute; z-index: 4; right: 20px; top: 86px; width: 222px; display: grid; grid-template-columns: 34px 1fr; gap: 5px 9px; align-items: center; border: 1px dashed rgba(82,98,15,.42); border-radius: 16px; background: rgba(251,255,218,.76); color: var(--ink); padding: 11px 13px; text-align: left; cursor: pointer; box-shadow: 0 9px 24px rgba(23,32,29,.1); backdrop-filter: blur(7px); }
+.real-world-empty > b { grid-row: 1/3; width: 34px; height: 34px; display: grid; place-items: center; border-radius: 50%; background: var(--ink); color: var(--acid); }
+.real-world-empty > span { font-size: 12px; font-weight: 900; line-height: 1.35; }
+.real-world-empty > small { color: var(--muted); font-size: 11px; }
+
+.timeline-bar { background: #eeeade; color: var(--ink); border-top: 1px solid rgba(23,32,29,.2); display: grid; grid-template-columns: 190px 1fr; min-width: 0; }
+.timeline-title { padding: 18px; display: flex; gap: 10px; align-items: center; border-right: 1px solid var(--line); }
+.timeline-title > span { font-size: 22px; }
+.timeline-title div { display: flex; flex-direction: column; gap: 4px; }
+.timeline-title strong { font: 700 11px var(--font-mono); letter-spacing: .09em; }
+.timeline-title small { color: var(--muted); font-size: 10px; }
+.timeline-items { display: flex; min-width: 0; overflow-x: auto; }
+.timeline-items > button { flex: 1 0 180px; max-width: 240px; border: 0; border-right: 1px solid var(--line); background: transparent; padding: 15px; display: grid; grid-template-columns: 33px 1fr; gap: 10px; text-align: left; align-items: center; cursor: pointer; }
+.timeline-items > button:hover { background: var(--acid); }
+.timeline-items > button > span { width: 33px; height: 33px; display: grid; place-items: center; border-radius: 50%; border: 1px solid; font: 700 11px var(--font-mono); }
+.timeline-items > button div { display: flex; flex-direction: column; gap: 4px; min-width: 0; }
+.timeline-items strong { font-size: 12px; }
+.timeline-items small { font-size: 10px; color: var(--muted); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
+.timeline-items > p { margin: auto 20px; font-size: 12px; color: var(--muted); }
+
+.guide-panel { position: fixed; z-index: 50; top: 86px; right: 18px; bottom: 18px; width: min(470px, calc(100vw - 36px)); background: #f1eee4; color: var(--ink); border: 1px solid var(--ink); box-shadow: 9px 9px 0 rgba(217,240,93,.88), 0 25px 70px rgba(0,0,0,.3); display: grid; grid-template-rows: 72px minmax(0,1fr) auto auto; }
+.guide-header { display: flex; align-items: center; gap: 11px; padding: 12px 14px; border-bottom: 1px solid var(--line); }
+.guide-orb { width: 39px; height: 39px; display: grid; place-items: center; border-radius: 50%; background: var(--ink); color: var(--acid); box-shadow: 2px 2px 0 var(--coral); }
+.guide-header > div:nth-child(2) { display: flex; flex-direction: column; gap: 3px; flex: 1; }
+.guide-header strong { font-size: 14px; }
+.guide-header small { color: var(--muted); font-size: 10px; display: flex; align-items: center; gap: 5px; }
+.guide-header small span { width: 5px; height: 5px; background: #66a56c; border-radius: 50%; }
+.guide-header button { width: 31px; height: 31px; border: 1px solid var(--line); background: transparent; cursor: pointer; border-radius: 50%; }
+.chat-stream { padding: 18px 16px; overflow-y: auto; display: flex; flex-direction: column; gap: 12px; background-image: linear-gradient(rgba(23,32,29,.04) 1px, transparent 1px); background-size: 100% 30px; }
+.chat-bubble { display: flex; gap: 8px; align-items: flex-start; }
+.chat-bubble > span { width: 28px; height: 28px; flex: 0 0 auto; display: grid; place-items: center; border-radius: 50%; background: var(--ink); color: var(--acid); font-size: 11px; }
+.chat-bubble p { margin: 0; padding: 12px 14px; background: #fff; border: 1px solid var(--line); font-size: 14px; line-height: 1.7; max-width: 88%; }
+.chat-bubble.user { flex-direction: row-reverse; }
+.chat-bubble.user > span { background: var(--coral); color: #fff; }
+.chat-bubble.user p { background: #ded8c9; }
+.guide-controls { border-top: 1px solid var(--line); padding: 14px 16px; max-height: 44vh; overflow-y: auto; }
+.guide-primary, .guide-demo { width: 100%; border: 1px solid var(--ink); padding: 13px 15px; cursor: pointer; display: flex; justify-content: space-between; align-items: center; font-size: 13px; font-weight: 800; }
+.guide-primary { background: var(--ink); color: #fff; box-shadow: 3px 3px 0 var(--acid); }
+.guide-demo { background: transparent; margin-top: 9px; }
+.guide-controls form { display: flex; flex-direction: column; gap: 11px; }
+.guide-controls label { display: flex; flex-direction: column; gap: 7px; font-size: 11px; color: var(--muted); font-weight: 700; }
+.guide-controls input, .guide-controls textarea, .guide-controls select { width: 100%; border: 1px solid rgba(23,32,29,.35); background: #fff; color: var(--ink); padding: 11px 12px; outline: none; border-radius: 0; font-size: 14px; }
+.guide-controls input:focus, .guide-controls textarea:focus, .guide-controls select:focus { border-color: var(--ink); box-shadow: 0 0 0 2px var(--acid); }
+.form-pair { display: grid; grid-template-columns: 1fr 1fr; gap: 9px; }
+.pressure-box textarea { min-height: 92px; resize: vertical; margin-top: 3px; }
+.pressure-actions { display: grid; grid-template-columns: 110px 1fr; gap: 8px; margin-top: 8px; }
+.voice-button { border: 1px solid var(--ink); background: transparent; cursor: pointer; font-size: 12px; }
+.voice-button.listening { background: var(--coral); color: #fff; animation: pulse 1.1s infinite; }
+.voice-note { color: var(--muted); display: block; font-size: 10px; margin-top: 8px; line-height: 1.55; }
+.kind-picker { display: grid; grid-template-columns: 1fr 1fr; gap: 7px; }
+.kind-picker button { display: flex; gap: 8px; align-items: center; border: 1px solid var(--line); background: #fff; padding: 11px; cursor: pointer; text-align: left; font-size: 12px; }
+.kind-picker button:hover { border-color: var(--ink); background: var(--acid); }
+.more-actions { display: flex; flex-direction: column; }
+.guide-footer { padding: 10px 14px; border-top: 1px solid var(--line); color: var(--muted); font-size: 9px; display: flex; justify-content: space-between; gap: 10px; line-height: 1.5; }
+
+.modal-shade { position: fixed; inset: 0; background: rgba(10,14,12,.68); backdrop-filter: blur(6px); z-index: 70; display: grid; place-items: center; padding: 20px; }
+.debt-detail, .npc-story { width: min(480px,100%); background: var(--paper); color: var(--ink); border: 1px solid; box-shadow: 8px 8px 0 var(--acid); padding: 35px; position: relative; }
+.debt-detail { max-height: min(780px, calc(100vh - 40px)); overflow-y: auto; }
+.person-detail { width: min(820px, 100%); max-height: min(900px, calc(100vh - 40px)); overflow-y: auto; background: var(--paper); color: var(--ink); border: 1px solid; box-shadow: 8px 8px 0 var(--acid); padding: 34px; position: relative; }
+.person-detail-head { display: grid; grid-template-columns: 108px 1fr; align-items: center; gap: 20px; margin-bottom: 20px; text-align: left; }
+.person-detail-head h2 { margin: 7px 0 5px; font-size: 29px; letter-spacing: -.035em; }
+.person-detail-head > div:last-child > p:last-child { margin: 0; color: var(--muted); font-size: 12px; line-height: 1.6; }
+.self-portrait { width: 108px; height: 108px; display: grid; place-items: center; overflow: hidden; border: 1px solid var(--ink); border-radius: 28px; background: radial-gradient(circle at 50% 34%, #fff 0 27%, #e1dbce 72%); box-shadow: 4px 4px 0 var(--coral); }
+.self-portrait-character { transform: scale(1.35) translateY(7px); transform-origin: center; }
+.profile-headline-grid { display: grid; grid-template-columns: 1.1fr .9fr; gap: 10px; margin-bottom: 13px; }
+.profile-total-card, .profile-source-card { min-height: 118px; border: 1px solid var(--ink); padding: 17px; display: flex; flex-direction: column; justify-content: center; gap: 5px; }
+.profile-total-card { background: var(--ink); color: #fff; }
+.profile-source-card { background: var(--acid); }
+.profile-total-card span, .profile-source-card span { opacity: .62; font: 800 10px var(--font-mono); letter-spacing: .1em; }
+.profile-total-card strong { color: var(--acid); font: 900 26px var(--font-mono); }
+.profile-source-card strong { font-size: 23px; }
+.profile-total-card small, .profile-source-card small { font-size: 11px; }
+.cashflow-panel, .debt-composition { border: 1px solid var(--line); background: #e8e3d7; padding: 18px; margin-top: 13px; text-align: left; }
+.section-title { display: flex; align-items: center; justify-content: space-between; gap: 12px; margin-bottom: 14px; }
+.section-title > div { display: flex; align-items: center; gap: 8px; }
+.section-title > div > span { width: 27px; height: 27px; display: grid; place-items: center; border-radius: 50%; background: var(--ink); color: var(--acid); }
+.section-title strong { font: 900 12px var(--font-mono); letter-spacing: .08em; }
+.section-title > em { color: var(--muted); font-size: 10px; font-style: normal; }
+.cashflow-panel.cashflow-negative { border-color: rgba(232,110,78,.55); background: rgba(232,110,78,.08); }
+.cashflow-equation { display: grid; grid-template-columns: 1fr auto 1fr auto 1fr auto 1.08fr; gap: 8px; align-items: stretch; }
+.cashflow-equation > div { min-width: 0; background: rgba(255,255,255,.62); border: 1px solid var(--line); padding: 12px; display: flex; flex-direction: column; gap: 7px; }
+.cashflow-equation > b { align-self: center; color: var(--muted); font-size: 16px; }
+.cashflow-equation small { color: var(--muted); font: 800 9px var(--font-mono); letter-spacing: .07em; }
+.cashflow-equation strong { overflow-wrap: anywhere; font: 800 13px var(--font-mono); }
+.cashflow-equation .cashflow-result { background: var(--ink); color: #fff; }
+.cashflow-equation .cashflow-result small { color: rgba(255,255,255,.6); }
+.cashflow-equation .cashflow-result strong { color: var(--acid); }
+.cashflow-negative .cashflow-result strong { color: #ff9a7e; }
+.cashflow-track { height: 14px; margin-top: 14px; display: flex; overflow: hidden; background: rgba(23,32,29,.1); border: 1px solid rgba(23,32,29,.18); }
+.cashflow-track i { display: block; height: 100%; }
+.living-segment { background: #7eb6ca; }
+.repayment-segment { background: var(--coral); }
+.remaining-segment { background: var(--acid); }
+.cashflow-legend { display: flex; gap: 14px; margin-top: 8px; color: var(--muted); font-size: 10px; }
+.cashflow-legend span { display: flex; align-items: center; gap: 5px; }
+.cashflow-legend i { width: 9px; height: 9px; display: inline-block; }
+.cashflow-empty { margin: 7px 0 0; color: var(--muted); font-size: 11px; line-height: 1.6; }
+.cashflow-edit { margin-top: 12px; border: 0; background: transparent; padding: 0; color: var(--ink); text-decoration: underline; cursor: pointer; font-size: 11px; font-weight: 800; }
+.debt-composition { background: transparent; }
+.composition-list { display: grid; gap: 7px; }
+.composition-list > button, .composition-list > div { width: 100%; border: 1px solid var(--line); background: #fff; padding: 12px; display: grid; grid-template-columns: 10px minmax(0,1fr) auto; gap: 11px; align-items: center; text-align: left; }
+.composition-list > button { cursor: pointer; }
+.composition-list > button:hover { border-color: var(--ink); transform: translateX(2px); }
+.composition-list > .composition-primary { border-color: #aabd38; background: #fbffd9; }
+.composition-list > p { margin: 0; color: var(--muted); font-size: 11px; }
+.composition-list > button > div:nth-child(2), .composition-list > div > div:nth-child(2) { display: flex; flex-direction: column; gap: 5px; }
+.composition-list strong { font-size: 12px; }
+.composition-list strong b { display: inline-block; margin-left: 5px; padding: 2px 5px; background: var(--acid); font: 900 8px var(--font-mono); }
+.composition-list strong u { display: inline-block; margin-left: 5px; padding: 2px 5px; border: 1px solid var(--line); color: var(--muted); font: 800 9px var(--font-mono); text-decoration: none; }
+.composition-list div > i { height: 6px; display: block; overflow: hidden; background: #ded8ca; }
+.composition-list div > i > em { display: block; height: 100%; background: linear-gradient(90deg,var(--coral),var(--acid)); }
+.composition-list small { color: var(--muted); font-size: 9px; }
+.composition-money { align-items: flex-end; text-align: right; }
+.composition-money strong { font: 800 12px var(--font-mono); }
+.profile-pressure { margin: 14px 0 0; border-left: 3px solid var(--coral); background: rgba(232,110,78,.08); padding: 13px 15px; color: var(--ink); font-size: 13px; line-height: 1.65; font-weight: 700; }
+.profile-privacy { margin: 12px 0 0; color: var(--muted); font-size: 10px; line-height: 1.6; }
+.modal-close { position: absolute; right: 15px; top: 15px; width: 32px; height: 32px; border: 1px solid; border-radius: 50%; background: transparent; cursor: pointer; }
+.detail-kicker { margin: 0; color: var(--muted); font: 700 11px var(--font-mono); letter-spacing: .1em; text-transform: uppercase; }
+.debt-detail h2 { margin: 18px 0 13px; font: 700 42px var(--font-mono); letter-spacing: -.05em; }
+.big-progress { height: 11px; background: #d6d1c5; overflow: hidden; }
+.big-progress span { display: block; height: 100%; background: linear-gradient(90deg,var(--coral),var(--acid)); }
+.progress-copy { color: var(--muted); font-size: 12px; }
+.progress-copy strong { color: var(--ink); }
+.original-money { margin: -6px 0 14px; color: var(--muted); font: 700 11px var(--font-mono); }
+.ability-meters { display: grid; gap: 12px; margin: 20px 0; padding: 16px; border: 1px solid var(--line); background: #e8e3d7; text-align: left; }
+.ability-meters > div > p { display: flex; justify-content: space-between; gap: 12px; margin: 0 0 7px; font-size: 11px; }
+.ability-meters > div > p span { color: var(--muted); }
+.ability-meters > div > p strong { font: 800 12px var(--font-mono); }
+.ability-meters i { display: block; height: 8px; overflow: hidden; background: rgba(23,32,29,.12); }
+.ability-meters i b { display: block; height: 100%; background: linear-gradient(90deg,var(--coral),var(--acid)); }
+.ability-meters i.burden b { background: linear-gradient(90deg,#e5b356,var(--coral)); }
+.ability-meters i.capacity b { background: linear-gradient(90deg,#7ab0c6,var(--acid)); }
+.ability-meters > small { color: var(--muted); font-size: 10px; line-height: 1.65; }
+.detail-grid { display: grid; grid-template-columns: 1fr 1fr; border-left: 1px solid var(--line); border-top: 1px solid var(--line); margin: 25px 0; }
+.detail-grid div { padding: 13px; border-right: 1px solid var(--line); border-bottom: 1px solid var(--line); display: flex; flex-direction: column; gap: 6px; }
+.detail-grid small { color: var(--muted); font-size: 10px; }
+.detail-grid strong { font-size: 13px; }
+.reality-note { background: #e3ded2; border-left: 3px solid var(--coral); padding: 11px; font-size: 11px; line-height: 1.6; color: var(--muted); }
+.reported-balance { display: flex; flex-direction: column; gap: 7px; margin: 16px 0; font-size: 11px; font-weight: 800; }
+.reported-balance input { border: 1px solid rgba(23,32,29,.38); background: #fff; padding: 11px; font: 700 15px var(--font-mono); outline: none; }
+.reported-balance input:focus { border-color: var(--ink); box-shadow: 0 0 0 2px var(--acid); }
+.reported-balance small { color: var(--muted); font-size: 10px; line-height: 1.55; font-weight: 400; }
+.payment-button { width: 100%; border: 1px solid var(--ink); background: var(--ink); color: #fff; padding: 14px; cursor: pointer; font-weight: 800; font-size: 13px; box-shadow: 3px 3px var(--acid); }
+.payment-button:disabled { background: #8c928d; border-color: #8c928d; cursor: default; box-shadow: none; }
+.detail-actions { display: grid; grid-template-columns: 1fr 1fr; gap: 8px; margin-top: 14px; }
+.detail-actions button { border: 1px solid var(--ink); background: transparent; padding: 12px; cursor: pointer; font-size: 12px; font-weight: 800; }
+.detail-actions button.primary { background: var(--ink); color: #fff; box-shadow: 3px 3px var(--acid); }
+.detail-actions button.danger { background: var(--coral); color: #fff; }
+.debt-edit-form { display: flex; flex-direction: column; gap: 10px; border-top: 1px solid var(--line); padding-top: 16px; }
+.debt-edit-form label { display: flex; flex-direction: column; gap: 6px; color: var(--muted); font-size: 10px; font-weight: 800; }
+.debt-edit-form input, .debt-edit-form select { width: 100%; border: 1px solid rgba(23,32,29,.35); background: #fff; color: var(--ink); padding: 11px; outline: none; font-size: 13px; }
+.debt-edit-form input:focus, .debt-edit-form select:focus { border-color: var(--ink); box-shadow: 0 0 0 2px var(--acid); }
+.sharing-note { display: block; color: var(--muted); font-size: 12px; line-height: 1.65; font-weight: 500; }
+
+.vault-panel { width: min(560px, 100%); max-height: min(820px, calc(100vh - 40px)); overflow-y: auto; background: var(--paper); color: var(--ink); border: 1px solid; box-shadow: 8px 8px 0 var(--acid); padding: 34px; position: relative; }
+.vault-panel h2 { margin: 12px 0 22px; font-size: 29px; letter-spacing: -.03em; }
+.discovery-consent { display: grid; grid-template-columns: 20px 1fr; gap: 11px; align-items: start; border: 1px solid var(--line); background: rgba(122,176,198,.12); padding: 15px; margin-bottom: 14px; cursor: pointer; }
+.discovery-consent input { width: 17px; height: 17px; margin: 1px 0 0; accent-color: var(--ink); }
+.discovery-consent span { display: block; }
+.discovery-consent strong { display: block; font-size: 13px; }
+.discovery-consent p { margin: 6px 0; color: var(--muted); font-size: 11px; line-height: 1.65; }
+.discovery-consent small { display: block; color: var(--muted); font-size: 10px; line-height: 1.55; }
+.vault-intro, .vault-connected { border: 1px solid var(--line); background: #e8e3d7; padding: 16px; margin-bottom: 14px; }
+.vault-intro strong, .vault-connected strong { font-size: 14px; }
+.vault-intro p, .vault-connected p { color: var(--muted); font-size: 11px; line-height: 1.65; margin: 7px 0 0; }
+.vault-connected { display: grid; grid-template-columns: 32px 1fr; gap: 11px; background: rgba(217,240,93,.24); }
+.vault-connected > span { width: 32px; height: 32px; display: grid; place-items: center; border-radius: 50%; background: var(--ink); color: var(--acid); }
+.vault-primary, .vault-secondary { width: 100%; border: 1px solid var(--ink); padding: 13px 14px; cursor: pointer; font-size: 12px; font-weight: 900; }
+.vault-primary { background: var(--ink); color: #fff; box-shadow: 3px 3px var(--acid); }
+.vault-secondary { background: transparent; }
+.vault-primary:disabled, .vault-secondary:disabled { opacity: .5; cursor: default; }
+.vault-divider { position: relative; border-top: 1px solid var(--line); margin: 27px 0 18px; text-align: center; }
+.vault-divider span { position: relative; top: -9px; background: var(--paper); padding: 0 8px; color: var(--muted); font-size: 10px; }
+.vault-code-input input, .danger-zone input { width: 100%; border: 1px solid rgba(23,32,29,.4); background: #fff; padding: 12px; font: 700 12px var(--font-mono); text-transform: uppercase; outline: none; margin-bottom: 9px; }
+.vault-code-input input:focus, .danger-zone input:focus { border-color: var(--ink); box-shadow: 0 0 0 2px var(--acid); }
+.vault-text-button { border: 0; background: transparent; color: var(--muted); text-decoration: underline; padding: 9px 0; cursor: pointer; font-size: 11px; }
+.recovery-card { border: 1px solid var(--ink); padding: 17px; margin: 14px 0; background: #fff; box-shadow: 4px 4px var(--coral); }
+.recovery-card > strong { font-size: 14px; }
+.recovery-card p { color: var(--muted); font-size: 11px; line-height: 1.6; }
+.recovery-card code { display: block; background: #202724; color: var(--acid); padding: 13px; font: 700 14px/1.5 var(--font-mono); letter-spacing: .05em; overflow-wrap: anywhere; }
+.recovery-card button { width: 100%; margin-top: 9px; border: 1px solid var(--ink); background: var(--acid); padding: 11px; cursor: pointer; font-size: 11px; font-weight: 900; }
+.vault-actions { display: grid; grid-template-columns: 1fr 1fr; gap: 8px; padding: 15px 0; border-bottom: 1px solid var(--line); }
+.vault-actions a, .vault-actions button { border: 1px solid var(--ink); background: transparent; padding: 12px; text-align: center; cursor: pointer; font-size: 11px; font-weight: 800; }
+.vault-actions small { grid-column: 1 / -1; color: var(--muted); font-size: 10px; }
+.danger-zone { margin-top: 20px; border-left: 3px solid var(--coral); background: rgba(232,110,78,.08); padding: 15px; }
+.danger-zone strong { font-size: 13px; }
+.danger-zone p { color: var(--muted); font-size: 10px; line-height: 1.6; }
+.danger-zone button { width: 100%; border: 1px solid var(--coral); background: var(--coral); color: #fff; padding: 11px; cursor: pointer; font-size: 11px; font-weight: 900; }
+.danger-zone button:disabled { opacity: .42; cursor: default; }
+.vault-error { color: #a53522; background: rgba(232,110,78,.12); padding: 10px; font-size: 11px; line-height: 1.55; }
+.beta-invite-entry { margin: 14px 0; border: 1px solid rgba(23,32,29,.25); border-radius: 16px; background: linear-gradient(135deg, rgba(217,240,93,.17), rgba(122,176,198,.11)); padding: 15px; }
+.beta-invite-entry > strong { font-size: 15px; }
+.beta-invite-entry > p { color: var(--muted); font-size: 12px; line-height: 1.65; }
+.beta-invite-entry > input { width: 100%; min-height: 45px; border: 1px solid rgba(23,32,29,.45); border-radius: 10px; background: #fff; color: var(--ink); padding: 11px; font: 850 14px var(--font-mono); text-transform: uppercase; }
+.beta-invite-entry > label { display: grid; grid-template-columns: 20px 1fr; align-items: start; gap: 9px; margin-top: 12px; color: var(--ink); font-size: 12px; font-weight: 700; line-height: 1.58; }
+.beta-invite-entry > label input { width: 18px; height: 18px; margin-top: 1px; accent-color: var(--ink); }
+.beta-signups-paused { border-left: 4px solid var(--coral); border-radius: 8px; background: #fff0e9; color: #743322; padding: 11px 12px; font-size: 13px; font-weight: 800; line-height: 1.55; }
+.npc-story { text-align: center; max-height: min(860px, calc(100vh - 40px)); overflow-y: auto; }
+.npc-portrait { width: 142px; height: 150px; display: grid; place-items: center; margin: 0 auto 18px; overflow: hidden; background: radial-gradient(circle at 50% 34%, #fff 0 25%, #e4ded1 69%, #d0c9ba 100%); border: 1px solid; border-radius: 32px; box-shadow: inset 0 -18px rgba(23,32,29,.05), 4px 4px 0 rgba(23,32,29,.12); }
+.portrait-character { transform: scale(1.72) translateY(7px); transform-origin: center; }
+.npc-story > p { font: 700 11px var(--font-mono); color: var(--muted); }
+.npc-story h2 { margin: 12px 0; font: 800 36px var(--font-mono); letter-spacing: -.05em; }
+.npc-story blockquote { margin: 18px 0; font-size: 17px; line-height: 1.65; font-weight: 700; }
+.npc-meters { margin: 18px 0; }
+.npc-light-summary { display: grid; grid-template-columns: 82px 1fr; gap: 13px; align-items: center; margin: 18px 0 12px; border: 1px solid rgba(23,32,29,.18); border-radius: 17px; background: linear-gradient(135deg, rgba(217,240,93,.2), rgba(122,176,198,.1)); padding: 14px; }
+.npc-light-summary > strong { width: 72px; height: 72px; display: grid; place-items: center; border-radius: 50%; background: radial-gradient(circle, #fff9ad, var(--acid) 54%, #9eb43b 100%); color: var(--ink); font: 900 20px var(--font-mono); box-shadow: 0 0 22px rgba(217,240,93,.5); }
+.npc-light-summary > div { display: flex; flex-direction: column; gap: 5px; }
+.npc-light-summary b { font-size: 13px; }
+.npc-light-summary span { color: var(--muted); font-size: 12px; line-height: 1.6; }
+.npc-story > .npc-light-button:last-child { width: 100%; border: 1px solid rgba(23,32,29,.18); border-radius: 14px; background: linear-gradient(90deg, var(--acid), #f4e879); box-shadow: 0 9px 20px rgba(120,138,34,.18); padding: 14px 18px; cursor: pointer; font-size: 13px; font-weight: 900; transition: transform .16s ease, box-shadow .16s ease; }
+.npc-story > .npc-light-button:last-child:hover { transform: translateY(-2px); box-shadow: 0 13px 26px rgba(120,138,34,.24); }
+.npc-story > .npc-light-button.light-sent:last-child { background: #e8e3d7; color: var(--muted); box-shadow: none; }
+.community-person-detail { box-shadow: 8px 8px 0 rgba(217,240,93,.88); }
+.real-story-portrait { position: relative; background: radial-gradient(circle at 50% 34%, #fff 0 27%, #eff7bd 72%); }
+.real-story-portrait > span { position: absolute; left: 50%; bottom: 7px; transform: translateX(-50%); border-radius: 999px; background: var(--ink); color: var(--acid); padding: 5px 8px; font: 900 9px var(--font-mono); white-space: nowrap; }
+.real-story-approach { display: flex; flex-direction: column; gap: 5px; border-left: 4px solid var(--acid); border-radius: 0 13px 13px 0; background: rgba(217,240,93,.18); padding: 12px 14px; }
+.real-story-approach span { color: var(--muted); font: 800 11px var(--font-mono); letter-spacing: .06em; }
+.real-story-approach strong { font-size: 15px; }
+.real-light-milestones { margin: 17px 0 12px; border: 1px solid rgba(23,32,29,.16); border-radius: 17px; background: linear-gradient(135deg, rgba(217,240,93,.2), rgba(122,176,198,.1)); padding: 15px; }
+.real-light-milestones > div:first-child { display: flex; align-items: baseline; justify-content: space-between; gap: 12px; }
+.real-light-milestones > div:first-child strong { font: 900 24px var(--font-mono); color: #657714; }
+.real-light-milestones > div:first-child span { color: var(--muted); font-size: 12px; font-weight: 800; }
+.milestone-dots { display: grid; grid-template-columns: repeat(3,1fr); gap: 8px; margin: 12px 0 9px; }
+.milestone-dots > span { display: flex; align-items: center; justify-content: center; gap: 5px; border-radius: 999px; background: rgba(23,32,29,.08); color: var(--muted); padding: 7px; font: 800 11px var(--font-mono); }
+.milestone-dots > span b { color: #aaa; }
+.milestone-dots > span.reached { background: var(--ink); color: #fff; box-shadow: 0 0 14px rgba(217,240,93,.28); }
+.milestone-dots > span.reached b { color: var(--acid); }
+.real-light-milestones > small { color: var(--muted); font-size: 12px; line-height: 1.55; }
+.real-story-actions { display: grid; grid-template-columns: 1fr 1.2fr; gap: 9px; margin-top: 13px; }
+.real-story-actions button { min-height: 48px; border: 1px solid rgba(23,32,29,.22); border-radius: 13px; background: #fff; color: var(--ink); padding: 11px 13px; font-size: 13px; font-weight: 900; cursor: pointer; }
+.real-story-actions .npc-light-button { background: linear-gradient(90deg, var(--acid), #f4e879); box-shadow: 0 8px 19px rgba(120,138,34,.18); }
+.real-story-actions .npc-light-button:disabled { background: #e8e3d7; color: var(--muted); box-shadow: none; cursor: default; }
+.npc-story.person-detail { width: min(820px, 100%); text-align: left; max-height: min(900px, calc(100vh - 40px)); }
+.npc-detail-head { grid-template-columns: 142px 1fr; }
+.npc-detail-head .npc-portrait { margin: 0; }
+.npc-detail-head .original-money { margin: 0; }
+.npc-source-hero { border: 1px solid #aabd38; background: var(--acid); padding: 13px 16px; display: grid; grid-template-columns: 1fr auto; gap: 3px 12px; align-items: center; }
+.npc-source-hero span { grid-column: 1/-1; color: rgba(23,32,29,.6); font: 800 9px var(--font-mono); letter-spacing: .1em; }
+.npc-source-hero strong { font-size: 19px; }
+.npc-source-hero em { font: 800 12px var(--font-mono); font-style: normal; }
+.npc-cashflow { margin-top: 0; }
+.npc-composition > div { cursor: default; }
+.npc-story.person-detail > button:last-child { width: 100%; margin-top: 14px; }
+
+.country-gate-shade { position: fixed; inset: 0; z-index: 100; display: grid; place-items: center; padding: 20px; background: rgba(10,14,12,.86); backdrop-filter: blur(9px); }
+.country-gate { width: min(610px,100%); max-height: calc(100vh - 40px); overflow-y: auto; position: relative; background: var(--paper); color: var(--ink); border: 1px solid; box-shadow: 9px 9px 0 var(--acid); padding: 38px; }
+.country-gate h2 { margin: 12px 0; font-size: 31px; letter-spacing: -.04em; }
+.country-intro { margin: 0 0 22px; color: var(--muted); font-size: 12px; line-height: 1.75; }
+.country-gate form { display: grid; gap: 13px; }
+.country-gate label { display: flex; flex-direction: column; gap: 6px; color: var(--muted); font-size: 11px; font-weight: 800; }
+.country-gate input, .country-gate select { width: 100%; border: 1px solid rgba(23,32,29,.38); background: #fff; color: var(--ink); padding: 12px; outline: none; font-size: 14px; }
+.country-gate input:focus, .country-gate select:focus { border-color: var(--ink); box-shadow: 0 0 0 2px var(--acid); }
+.country-gate input[readonly] { background: #ded8c9; }
+.country-pair { display: grid; grid-template-columns: 1fr 1.4fr; gap: 10px; }
+.country-budget-grid { display: grid; grid-template-columns: .72fr 1.15fr 1.15fr; gap: 10px; }
+.budget-privacy-note { margin: 0; padding: 10px 12px; border: 1px dashed var(--line); color: var(--muted); font-size: 10px; line-height: 1.6; }
+.rate-note { margin: 0; border-left: 3px solid #7ab0c6; padding: 10px 12px; background: rgba(122,176,198,.12); color: var(--muted); font-size: 10px; line-height: 1.6; }
+
+.reset-button { position: fixed; left: 331px; bottom: 124px; z-index: 19; border: 1px solid rgba(23,32,29,.3); background: rgba(243,240,230,.86); color: var(--ink); backdrop-filter: blur(4px); padding: 9px 12px; font-size: 12px; cursor: pointer; }
+.reality-rules { position: fixed; z-index: 18; right: 18px; bottom: 130px; width: 255px; background: rgba(32,39,36,.92); border: 1px solid rgba(255,255,255,.15); padding: 14px; backdrop-filter: blur(7px); }
+.reality-rules > p { margin: 0 0 10px; color: var(--acid); font: 700 10px var(--font-mono); letter-spacing: .1em; }
+.reality-rules ol { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; gap: 7px; }
+.reality-rules li { display: flex; gap: 7px; color: rgba(243,240,230,.68); font-size: 10px; line-height: 1.5; }
+.reality-rules li span { width: 17px; height: 17px; display: grid; place-items: center; flex: 0 0 auto; border: 1px solid rgba(255,255,255,.2); border-radius: 50%; color: var(--paper); font: 700 8px var(--font-mono); }
+.mobile-controls { display: none; }
+
+/* Readability system: no essential copy is allowed to collapse into micro text. */
+.game-shell { font-size: 15px; }
+.game-shell small { font-size: 12px; line-height: 1.55; }
+.game-shell label { font-size: 13px; line-height: 1.5; }
+.game-shell input, .game-shell textarea, .game-shell select { font-size: 15px; min-height: 44px; }
+.game-shell button, .locale-link { line-height: 1.35; }
+.game-brand small, .world-date, .save-state, .hud-kicker, .hud-total > span,
+.hud-focus-card > span, .hud-focus-card em, .hud-cashflow > span, .hud-cashflow small,
+.hud-tip p, .district strong, .npc-tag-label, .npc-tag b, .npc-tag i, .npc small, .npc em,
+.player-name, .player-total-debt small, .player-total-debt > span, .player-total-debt > i,
+.timeline-title strong, .timeline-title small, .timeline-items small, .guide-header small,
+.guide-controls label, .voice-note, .guide-footer, .profile-total-card span,
+.profile-source-card span, .section-title > em, .cashflow-equation small, .cashflow-legend,
+.cashflow-empty, .cashflow-edit, .composition-list small, .profile-privacy, .detail-kicker,
+.original-money, .ability-meters > div > p, .ability-meters > small, .detail-grid small,
+.reality-note, .reported-balance, .reported-balance small, .debt-edit-form label,
+.discovery-consent p, .discovery-consent small, .vault-intro p, .vault-connected p,
+.vault-divider span, .vault-text-button, .recovery-card p, .recovery-card button,
+.vault-actions a, .vault-actions button, .vault-actions small, .danger-zone p,
+.danger-zone button, .vault-error, .npc-story > p, .npc-source-hero span,
+.country-gate label, .budget-privacy-note, .rate-note, .reality-rules > p,
+.reality-rules li { font-size: 12px; }
+.debt-mini-card strong { font-size: 14px; }
+.debt-mini-card strong b, .composition-list strong b, .composition-list strong u { font-size: 11px; }
+.debt-mini-card small, .debt-mini-card i, .timeline-title strong,
+.timeline-items > button > span, .composition-list strong, .composition-money strong,
+.ability-meters > div > p strong, .detail-grid strong { font-size: 13px; }
+.orbit-label span { font-size: 12px; font-weight: 800; }
+.orbit-label strong { font-size: 14px; }
+.orbit-label i { width: 25px; height: 25px; font-size: 10px; }
+.reality-rules li span { width: 19px; height: 19px; font-size: 10px; }
+.chat-bubble p { font-size: 15px; }
+.guide-primary, .guide-demo, .kind-picker button, .voice-button,
+.payment-button, .detail-actions button, .vault-primary, .vault-secondary,
+.npc-story > button:last-child { font-size: 14px; }
+
+/* Game-score numbers: full digits, steady alignment, and high contrast. */
+.hud-total strong, .hud-metrics strong, .hud-focus-card em, .hud-cashflow strong,
+.npc-tag strong, .npc-tag i, .player-total-debt strong, .orbit-label strong,
+.timeline-items > button > span, .debt-detail h2, .profile-total-card strong,
+.profile-source-card small, .cashflow-equation strong, .composition-money strong,
+.npc-story h2, .npc-source-hero em {
+ font-variant-numeric: tabular-nums lining-nums;
+ font-feature-settings: "tnum" 1, "lnum" 1;
+}
+.hud-total strong, .player-total-debt strong, .npc-tag strong {
+ letter-spacing: .015em;
+ text-shadow: 2px 2px 0 rgba(23,32,29,.22);
+}
+.hud-total strong {
+ width: fit-content;
+ color: var(--acid);
+ padding: 7px 10px;
+ border: 1px solid rgba(217,240,93,.5);
+ background: repeating-linear-gradient(135deg, rgba(217,240,93,.08) 0 5px, transparent 5px 10px);
+ box-shadow: 3px 3px 0 rgba(217,240,93,.16);
+}
+.player-total-debt strong {
+ padding: 4px 8px;
+ color: var(--acid);
+ background: linear-gradient(180deg, rgba(255,255,255,.08), transparent);
+ border-top: 1px dashed rgba(255,255,255,.22);
+ border-bottom: 1px dashed rgba(255,255,255,.22);
+}
+.npc-tag strong { color: #fff; }
+
+@keyframes pulse { 50% { opacity: .6; } }
+@keyframes character-step { 50% { transform: translateY(-3px); } }
+@keyframes self-aura { 50% { transform: scale(1.06); opacity: .72; } }
+@keyframes light-twinkle { 0%,100% { transform: translateY(4px) scale(.65); opacity: .3; } 50% { transform: translateY(-5px) scale(1.15); opacity: 1; } }
+@keyframes light-ring { 50% { transform: translateX(-50%) scale(1.16); opacity: .36; } }
+@keyframes light-arrival { 0% { transform: translateX(-50%) scale(.35); opacity: 0; } 45% { transform: translateX(-50%) scale(1.45); opacity: 1; } 100% { transform: translateX(-50%) scale(1); opacity: 1; } }
+@keyframes light-character-bounce { 45% { transform: translateY(-10px); } }
+@keyframes light-toast { 0% { transform: translate(-50%,18px) scale(.86); opacity: 0; } 18%,78% { transform: translate(-50%,0) scale(1); opacity: 1; } 100% { transform: translate(-50%,-8px) scale(.96); opacity: 0; } }
+@keyframes story-light-wave { 0% { transform: scale(.25); opacity: 0; } 35% { opacity: 1; } 100% { transform: scale(1.8); opacity: 0; } }
+@keyframes story-light-label { 0% { transform: translateY(10px) scale(.8); opacity: 0; } 20%,78% { transform: translateY(0) scale(1); opacity: 1; } 100% { transform: translateY(-8px) scale(.96); opacity: 0; } }
+@keyframes burden-balloon-float { 0%,100% { transform: translateY(2px) rotate(-2deg); } 50% { transform: translateY(-5px) rotate(3deg); } }
+@keyframes burden-cloud-float { 0%,100% { transform: translateX(0); } 50% { transform: translateX(-5px); } }
+@keyframes burden-lift-arrival { 0% { opacity: 0; transform: translate(-50%,18px) scale(.45); } 55% { opacity: 1; transform: translate(-50%,-7px) scale(1.16); } 100% { opacity: 1; transform: translateX(-50%) scale(1); } }
+
+@media (max-width: 1180px) {
+ .game-topbar { grid-template-columns: minmax(0,1fr) auto; grid-template-areas: "brand date" "actions actions"; }
+ .top-actions { justify-content: flex-start; }
+}
+
+@media (max-width: 980px) {
+ .game-topbar { grid-template-columns: minmax(0,1fr) auto; grid-template-areas: "brand brand" "actions actions"; }
+ .world-date, .save-state { display: none; }
+ .top-actions > .vault-status { max-width: 150px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
+ .game-layout { grid-template-columns: 270px minmax(0,1fr); }
+ .guide-panel { top: 82px; }
+ .reality-rules { display: none; }
+ .reset-button { left: 280px; }
+}
+
+@media (max-width: 720px) {
+ .game-shell { height: auto; min-height: 100vh; overflow: auto; }
+ .game-topbar { min-height: 64px; height: auto; grid-template-columns: minmax(0,1fr); grid-template-areas: "brand" "actions"; padding: 9px 12px; gap: 8px; }
+ .game-brand small { display: none; }
+ .game-brand strong { font-size: 14px; }
+ .planet-mark { width: 34px; height: 34px; }
+ .top-actions { width: 100%; flex-wrap: nowrap; justify-content: flex-start; gap: 6px; overflow-x: auto; overscroll-behavior-x: contain; scrollbar-width: none; padding-bottom: 2px; }
+ .top-actions::-webkit-scrollbar { display: none; }
+ .top-actions > button, .top-actions > a, .top-actions > .vault-status { flex: 0 0 auto; padding: 8px 10px; font-size: 12px; }
+ .locale-link { padding: 8px 9px; font-size: 12px; }
+ .game-layout { flex: none; width: 100%; display: flex; flex-direction: column-reverse; height: auto; min-height: 0; }
+ .debt-hud { border: 0; padding: 18px 14px 90px; max-height: none; }
+ .hud-total { display: grid; grid-template-columns: 1fr auto; align-items: end; }
+ .hud-total small { grid-column: 1/-1; }
+ .hud-total strong { font-size: 26px; }
+ .hud-total > span { text-align: right; }
+ .world-wrap { grid-template-rows: 560px 108px; }
+ .world-stage { min-height: 560px; }
+ .world-message { left: 14px; top: 13px; max-width: 190px; }
+ .world-growth-status { top: 8px; max-width: calc(100% - 16px); width: calc(100% - 16px); justify-content: center; border-radius: 13px; padding: 7px 9px; white-space: normal; text-align: center; }
+ .world-growth-status b { display: none; }
+ .district { transform: scale(.76); }
+ .npc { transform: translate(-50%,-50%) scale(.85); }
+ .npc:hover, .npc-near { transform: translate(-50%,-54%) scale(.85); }
+ .player { transition: left .08s linear, top .08s linear; }
+ .orbit-label { transform: translate(calc(-50% + var(--orbit-x)), calc(-50% + var(--orbit-y))) scale(.78); }
+ .orbit-more-label { transform: translateX(-50%) scale(.78); transform-origin: center; }
+ .timeline-bar { grid-template-columns: 142px 1fr; }
+ .timeline-title { padding: 12px; }
+ .guide-panel { top: 70px; right: 8px; bottom: 8px; width: calc(100vw - 16px); }
+ .guide-controls { max-height: 48vh; }
+ .guide-footer { display: none; }
+ .person-detail { width: calc(100vw - 20px); padding: 28px 22px; }
+ .person-detail-head { grid-template-columns: 88px 1fr; gap: 14px; }
+ .self-portrait { width: 88px; height: 88px; }
+ .person-detail-head h2 { font-size: 23px; }
+ .npc-detail-head { grid-template-columns: 112px 1fr; }
+ .npc-detail-head .npc-portrait { width: 112px; height: 122px; }
+ .cashflow-equation { grid-template-columns: 1fr 1fr; }
+ .cashflow-equation > b { display: none; }
+ .cashflow-equation .cashflow-result { grid-column: 1/-1; }
+ .country-budget-grid { grid-template-columns: 1fr; }
+ .mobile-controls { position: absolute; left: 16px; bottom: 18px; width: 112px; height: 112px; display: grid; grid-template-columns: repeat(3,1fr); grid-template-rows: repeat(3,1fr); gap: 3px; z-index: 15; }
+ .mobile-controls button { border: 1px solid rgba(23,32,29,.35); background: rgba(243,240,230,.8); border-radius: 5px; font-weight: 800; }
+ .mobile-controls button:nth-child(1) { grid-column: 2; grid-row: 1; }
+ .mobile-controls button:nth-child(2) { grid-column: 1; grid-row: 2; }
+ .mobile-controls button:nth-child(3) { grid-column: 3; grid-row: 2; }
+ .mobile-controls button:nth-child(4) { grid-column: 2; grid-row: 3; }
+ .reset-button { position: absolute; left: auto; right: 12px; bottom: 108px; }
+}
+
+@media (max-width: 430px) {
+ .game-topbar { padding: 0 8px; }
+ .planet-mark { width: 32px; height: 32px; }
+ .game-brand { gap: 7px; }
+ .game-brand strong { font-size: 13px; letter-spacing: .04em; }
+ .top-actions > .vault-status { display: none; }
+ .top-actions > button { width: auto; max-width: 86px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; padding: 8px 9px; color: var(--ink); font-size: 12px; }
+ .locale-link { padding: 8px; font-size: 12px; }
+ .world-wrap { grid-template-rows: 580px 112px; }
+ .world-stage { min-height: 580px; }
+ .form-pair { grid-template-columns: 1fr; }
+ .kind-picker { grid-template-columns: 1fr 1fr; }
+ .debt-detail, .npc-story, .person-detail { padding: 30px 20px; }
+ .debt-detail h2 { font-size: 34px; }
+ .vault-panel { padding: 30px 20px; }
+ .vault-panel h2 { font-size: 24px; }
+ .vault-actions { grid-template-columns: 1fr; }
+ .vault-actions small { grid-column: 1; }
+ .country-gate { padding: 32px 20px; }
+ .country-gate h2 { font-size: 25px; }
+ .country-pair { grid-template-columns: 1fr; }
+ .profile-headline-grid { grid-template-columns: 1fr; }
+ .person-detail-head, .npc-detail-head { grid-template-columns: 1fr; }
+ .self-portrait, .npc-detail-head .npc-portrait { margin: 0 auto; }
+ .person-detail-head > div:last-child { text-align: center; }
+ .profile-total-card, .profile-source-card { min-height: 98px; }
+ .composition-list > button, .composition-list > div { grid-template-columns: 9px minmax(0,1fr); }
+ .composition-money { grid-column: 2; align-items: flex-start; text-align: left; }
+ .section-title { align-items: flex-start; flex-direction: column; }
+ .player-total-debt { top: -109px; min-width: 220px; padding: 9px 11px; }
+ .player-total-debt strong { font-size: 19px; }
+ .npc { transform: translate(-50%,-50%) scale(.82); }
+ .npc:hover, .npc-near { transform: translate(-50%,-54%) scale(.82); }
+ .timeline-title { padding: 10px; }
+ .timeline-title > span { display: none; }
+ .timeline-bar { grid-template-columns: 105px 1fr; }
+ .timeline-items > button { flex-basis: 170px; padding: 12px; }
+}
+
+@media (prefers-reduced-motion: reduce) {
+ *, *::before, *::after { animation: none !important; transition: none !important; }
+}
+
+/* Ongoing Kian guidance */
+.advisor-controls { display: flex; flex-direction: column; gap: 11px; }
+.community-hud-button { width: 100%; margin-top: 9px; border: 1px solid var(--acid); background: rgba(217,240,93,.1); color: var(--acid); padding: 11px; font-size: 13px; font-weight: 900; cursor: pointer; }
+.safety-hud-link { display: block; margin-top: 7px; border-radius: 9px; background: rgba(255,255,255,.06); color: rgba(255,255,255,.66); padding: 9px 10px; font: 800 9px var(--font-mono); line-height: 1.45; }
+.vault-safety-link { display: block; margin: -4px 0 15px; border-radius: 11px; background: rgba(122,176,198,.13); color: #3d7180; padding: 10px 12px; font-size: 12px; font-weight: 900; line-height: 1.5; }
+.advisor-snapshot { border: 1px solid var(--ink); background: rgba(217,240,93,.3); padding: 13px; display: flex; flex-direction: column; gap: 5px; }
+.advisor-snapshot strong { font-size: 14px; }
+.advisor-snapshot span { font: 700 13px var(--font-mono); line-height: 1.55; }
+.advisor-prompts { display: grid; grid-template-columns: repeat(3,1fr); gap: 6px; }
+.advisor-prompts button { min-height: 40px; border: 1px solid var(--line); background: #fff; color: var(--ink); cursor: pointer; font-size: 13px; font-weight: 800; }
+.advisor-form textarea { min-height: 92px; resize: vertical; }
+.advisor-form > div { display: grid; grid-template-columns: 112px 1fr; gap: 8px; }
+.advisor-boundary { display: block; color: var(--muted); font-size: 12px; line-height: 1.65; }
+.advisor-consent { display: grid !important; grid-template-columns: 22px 1fr; align-items: start; gap: 9px; border: 1px solid rgba(41,45,37,.24); border-radius: 14px; background: rgba(255,255,255,.72); padding: 12px; color: var(--ink); font-size: 13px; font-weight: 650; line-height: 1.55; }
+.advisor-consent input { width: 19px; height: 19px; margin: 1px 0 0; accent-color: #181b16; }
+.advisor-vault-needed { min-height: 44px; border: 1px solid var(--ink); border-radius: 14px; background: rgba(217,240,93,.45); color: var(--ink); padding: 10px 13px; font-size: 13px; font-weight: 850; cursor: pointer; }
+.advisor-error { margin: 0; border-left: 4px solid #cf6a46; border-radius: 8px; background: #fff0e9; color: #6d2e20; padding: 10px 12px; font-size: 13px; font-weight: 750; line-height: 1.5; }
+.advisor-result { display: grid; gap: 10px; border: 1px solid var(--ink); border-radius: 16px; background: rgba(243,246,229,.9); padding: 12px; }
+.advisor-result-head { display: flex; align-items: center; justify-content: space-between; gap: 10px; }
+.advisor-result-head strong { font-size: 14px; }
+.advisor-result-head span { border-radius: 999px; background: var(--ink); color: #fff; padding: 5px 9px; font: 750 11px var(--font-mono); }
+.advisor-risk-self_harm, .advisor-risk-scam, .advisor-risk-illegal_collection, .advisor-risk-legal_deadline, .advisor-risk-medical { border-color: #bd4a3d; background: #fff1ed; }
+.advisor-drafts { display: grid; gap: 8px; }
+.advisor-drafts > b { font-size: 13px; }
+.advisor-drafts article { display: grid; gap: 7px; border: 1px solid rgba(41,45,37,.25); border-radius: 13px; background: #fff; padding: 11px; }
+.advisor-drafts article > div { display: flex; justify-content: space-between; gap: 10px; align-items: start; }
+.advisor-drafts article strong { font-size: 13px; line-height: 1.45; }
+.advisor-drafts article span { font: 800 12px var(--font-mono); text-align: right; }
+.advisor-drafts article p, .advisor-drafts article small { margin: 0; color: var(--muted); font-size: 12px; line-height: 1.5; }
+.advisor-drafts article button { min-height: 38px; border: 1px solid var(--ink); border-radius: 10px; background: var(--lime); color: var(--ink); font-size: 12px; font-weight: 850; cursor: pointer; }
+
+/* Statement facts and three-lens repayment comparison */
+.strategy-fields { min-width: 0; margin: 2px 0; border: 1px solid rgba(23,32,29,.24); border-radius: 14px; background: rgba(122,176,198,.09); padding: 13px; }
+.strategy-fields legend { padding: 0 7px; color: var(--ink); font-size: 13px; font-weight: 900; }
+.strategy-fields > small { display: block; margin-top: 9px; color: var(--muted); font-size: 12px; line-height: 1.6; }
+.strategy-fields input, .strategy-fields select { font-size: 15px; }
+.repayment-strategy-panel { margin-top: 13px; border: 1px solid rgba(23,32,29,.24); border-radius: 18px; background: linear-gradient(145deg, rgba(255,255,255,.9), rgba(217,240,93,.11)); padding: 18px; text-align: left; }
+.strategy-readiness { display: flex; flex-wrap: wrap; gap: 7px; margin: 12px 0; }
+.strategy-readiness span { border: 1px solid rgba(23,32,29,.18); border-radius: 999px; background: #fff; padding: 7px 10px; font: 850 11px var(--font-mono); }
+.strategy-card-grid { display: grid; grid-template-columns: repeat(3,minmax(0,1fr)); gap: 9px; }
+.strategy-card-grid article { min-width: 0; display: flex; flex-direction: column; border: 1px solid rgba(23,32,29,.2); border-radius: 16px; background: #fff; padding: 14px; box-shadow: 0 7px 18px rgba(23,32,29,.06); }
+.strategy-card-grid article.strategy-incomplete { background: #eeeae0; box-shadow: none; }
+.strategy-card-grid article.strategy-safety { background: rgba(122,176,198,.11); }
+.strategy-card-grid header { display: flex; align-items: center; gap: 9px; }
+.strategy-card-grid header > span { width: 32px; height: 32px; flex: 0 0 auto; display: grid; place-items: center; border-radius: 10px; background: var(--ink); color: var(--acid); font: 900 11px var(--font-mono); }
+.strategy-card-grid header div { display: flex; flex-direction: column; gap: 2px; }
+.strategy-card-grid header strong { font-size: 13px; line-height: 1.3; }
+.strategy-card-grid header small { color: var(--muted); font-size: 11px; }
+.strategy-card-grid h3 { margin: 18px 0 7px; font-size: 19px; letter-spacing: -.025em; }
+.strategy-card-grid p { margin: 0 0 9px; color: var(--muted); font-size: 13px; line-height: 1.65; }
+.strategy-card-grid article > small { margin-bottom: 10px; color: #9a512f; font-size: 11px; line-height: 1.5; }
+.strategy-card-grid button { width: 100%; min-height: 39px; margin-top: auto; border: 1px solid var(--ink); border-radius: 11px; background: var(--ink); color: #fff; font-size: 12px; font-weight: 900; cursor: pointer; }
+.strategy-card-grid button:hover { background: var(--acid); color: var(--ink); }
+.strategy-boundary { margin: 12px 0 0; border-left: 3px solid var(--coral); padding: 6px 0 6px 10px; color: var(--muted); font-size: 12px; line-height: 1.6; }
+
+@media (max-width: 760px) {
+ .strategy-card-grid { grid-template-columns: 1fr; }
+ .strategy-card-grid article { min-height: 0; }
+ .strategy-readiness span { flex: 1 1 auto; text-align: center; }
+}
+
+/* Real prepayment and once-daily real extra-income entry */
+.special-payment-tools, .payment-history { margin-top: 18px; border: 1px solid var(--ink); padding: 15px; background: #fff; }
+.special-payment-tools .section-title, .payment-history .section-title { margin-bottom: 12px; }
+.special-tabs { display: grid; grid-template-columns: 1fr 1fr; gap: 5px; margin-bottom: 13px; }
+.special-tabs button { border: 1px solid var(--line); background: #eee9dc; color: var(--ink); min-height: 42px; font-size: 14px; font-weight: 800; cursor: pointer; }
+.special-tabs button.active { background: var(--ink); color: var(--acid); border-color: var(--ink); }
+.special-form { display: flex; flex-direction: column; gap: 11px; }
+.special-form > p { margin: 0; font-size: 13px; line-height: 1.7; color: var(--muted); }
+.special-form label { display: flex; flex-direction: column; gap: 6px; color: var(--muted); font-size: 13px; font-weight: 800; }
+.special-form input, .special-form select { width: 100%; min-height: 43px; border: 1px solid rgba(23,32,29,.45); background: #fff; color: var(--ink); padding: 10px 11px; font-size: 15px; outline: none; }
+.special-form input:focus, .special-form select:focus { border-color: var(--ink); box-shadow: 0 0 0 2px var(--acid); }
+.special-form > small { color: var(--muted); font-size: 12px; line-height: 1.65; }
+.special-submit { border: 1px solid var(--ink); background: var(--ink); color: #fff; min-height: 46px; padding: 11px 14px; font-size: 14px; font-weight: 900; cursor: pointer; box-shadow: 3px 3px 0 var(--acid); }
+.special-submit:disabled { opacity: .45; cursor: not-allowed; box-shadow: none; }
+.lucky-form { background: linear-gradient(135deg, rgba(217,240,93,.18), rgba(122,176,198,.12)); padding: 12px; border: 1px dashed var(--ink); }
+.lucky-submit { color: var(--ink); background: var(--acid); }
+.daily-chance { display: flex; align-items: center; gap: 10px; border: 1px solid var(--ink); background: #fff; padding: 10px; }
+.daily-chance b { width: 28px; height: 28px; display: grid; place-items: center; border-radius: 50%; background: var(--coral); color: #fff; font: 900 14px var(--font-mono); }
+.daily-chance span { font-size: 13px; font-weight: 800; }
+.daily-chance.used { opacity: .7; }
+.daily-chance.used b { background: #68956f; }
+.payment-tool-message { margin: 12px 0 0; border-left: 4px solid var(--coral); background: rgba(232,110,78,.1); padding: 10px 12px; color: var(--ink); font-size: 13px; line-height: 1.6; }
+.payment-history { display: flex; flex-direction: column; gap: 7px; }
+.payment-history > div:not(.section-title) { display: grid; grid-template-columns: 1fr auto; gap: 4px 10px; border-top: 1px solid var(--line); padding-top: 9px; }
+.payment-history > div > span { font-size: 13px; font-weight: 800; }
+.payment-history > div > strong { font: 800 13px var(--font-mono); }
+.payment-history > div > small { grid-column: 1/-1; color: var(--muted); font-size: 12px; }
+
+/* Reviewed anonymous community and privacy-thresholded world data */
+.community-panel { width: min(880px, 100%); max-height: min(900px, calc(100vh - 40px)); overflow-y: auto; position: relative; background: var(--paper); color: var(--ink); border: 1px solid var(--ink); box-shadow: 9px 9px 0 var(--acid); padding: 32px; }
+.community-head { display: flex; align-items: center; gap: 15px; padding-right: 42px; }
+.community-head > span { width: 52px; height: 52px; flex: 0 0 auto; display: grid; place-items: center; border-radius: 50%; background: var(--ink); color: var(--acid); font-size: 22px; box-shadow: 3px 3px 0 var(--coral); }
+.community-head p { margin: 0 0 4px; color: var(--muted); font: 800 12px var(--font-mono); letter-spacing: .08em; }
+.community-head h2 { margin: 0 0 5px; font-size: 27px; letter-spacing: -.03em; }
+.community-head small { color: var(--muted); font-size: 13px; line-height: 1.5; }
+.community-safety-strip { display: flex; align-items: center; gap: 11px; margin: 18px 0 14px; border: 1px solid var(--ink); background: rgba(122,176,198,.16); padding: 11px 13px; }
+.community-safety-strip b { width: 25px; height: 25px; flex: 0 0 auto; display: grid; place-items: center; border-radius: 50%; color: #fff; background: var(--coral); }
+.community-safety-strip span { font-size: 13px; line-height: 1.55; font-weight: 700; }
+.community-tabs { display: grid; grid-template-columns: repeat(3,1fr); border-bottom: 1px solid var(--ink); margin-bottom: 14px; }
+.community-tabs button { border: 0; border-right: 1px solid var(--line); background: transparent; color: var(--muted); min-height: 48px; padding: 10px; font-size: 14px; font-weight: 900; cursor: pointer; }
+.community-tabs button.active { background: var(--ink); color: var(--acid); }
+.community-tabs i { display: inline-grid; place-items: center; min-width: 22px; height: 22px; margin-left: 4px; border-radius: 11px; background: rgba(255,255,255,.16); font: normal 800 11px var(--font-mono); }
+.community-feed, .community-mine, .community-insights { display: flex; flex-direction: column; gap: 12px; }
+.community-empty { min-height: 150px; border: 1px dashed var(--line); padding: 28px; display: flex; flex-direction: column; align-items: center; justify-content: center; gap: 10px; text-align: center; }
+.community-empty strong { font-size: 17px; }
+.community-empty span, .community-empty p { max-width: 620px; color: var(--muted); font-size: 14px; line-height: 1.65; }
+.community-empty button { border: 1px solid var(--ink); background: var(--ink); color: #fff; padding: 10px 15px; font-size: 14px; font-weight: 800; cursor: pointer; }
+.community-story { position: relative; overflow: hidden; border: 1px solid var(--ink); background: #fff; padding: 17px; transition: box-shadow .2s ease, transform .2s ease; }
+.community-story.story-light-burst { transform: translateY(-2px); box-shadow: 0 14px 34px rgba(116,135,32,.2), 0 0 0 4px rgba(217,240,93,.18); }
+.community-story.story-light-burst::after { content: ""; position: absolute; right: 38px; bottom: 31px; width: 96px; height: 96px; border-radius: 50%; background: radial-gradient(circle, rgba(255,252,196,.94), rgba(217,240,93,.45) 42%, transparent 72%); pointer-events: none; animation: story-light-wave 1.2s ease-out both; }
+.story-meta { display: grid; grid-template-columns: 35px 1fr auto; gap: 10px; align-items: center; }
+.story-meta > span { font-size: 25px; }
+.story-meta > div { display: flex; flex-direction: column; gap: 3px; }
+.story-meta strong { font-size: 15px; }
+.story-meta small, .story-meta time { color: var(--muted); font-size: 12px; }
+.approach-pill { display: inline-flex; width: fit-content; margin: 12px 0 0; background: rgba(217,240,93,.44); border: 1px solid rgba(23,32,29,.25); padding: 6px 9px; font-size: 12px; font-weight: 900; }
+.community-story > p { margin: 13px 0; font-size: 15px; line-height: 1.75; }
+.community-story footer { display: flex; justify-content: space-between; gap: 8px; }
+.community-story footer button { border: 1px solid var(--line); background: transparent; color: var(--ink); padding: 9px 11px; font-size: 13px; font-weight: 800; cursor: pointer; }
+.community-story footer button.encouraged { background: var(--acid); }
+.community-story footer button:disabled { cursor: default; opacity: .65; }
+.story-light-arrival { position: absolute; z-index: 3; right: 16px; bottom: 58px; border-radius: 999px; background: var(--ink); color: var(--acid); padding: 8px 11px; box-shadow: 0 8px 18px rgba(23,32,29,.23), 0 0 16px rgba(217,240,93,.32); font-size: 12px; font-weight: 900; animation: story-light-label 1.3s ease both; }
+.report-form, .story-composer { margin-top: 13px; border-top: 1px dashed var(--line); padding-top: 13px; display: flex; flex-direction: column; gap: 11px; }
+.report-form label, .story-composer label { display: flex; flex-direction: column; gap: 6px; color: var(--muted); font-size: 13px; font-weight: 800; }
+.report-form input, .report-form select, .report-form textarea, .story-composer select, .story-composer textarea { border: 1px solid rgba(23,32,29,.4); background: #fff; color: var(--ink); padding: 10px; min-height: 43px; font-size: 15px; }
+.report-form textarea { min-height: 72px; }
+.story-composer textarea { min-height: 130px; resize: vertical; }
+.story-composer label > small { text-align: right; font-size: 12px; }
+.report-form > div { display: flex; justify-content: flex-end; gap: 8px; }
+.report-form button, .story-composer > button { border: 1px solid var(--ink); background: var(--ink); color: #fff; padding: 11px 14px; font-size: 14px; font-weight: 900; cursor: pointer; }
+.story-composer > button:disabled { opacity: .45; }
+.submission-list { display: flex; flex-direction: column; gap: 9px; margin-top: 14px; }
+.submission-list article { display: grid; grid-template-columns: auto 1fr; gap: 7px 10px; border: 1px solid var(--line); background: #fff; padding: 13px; }
+.submission-list strong { font-size: 14px; }
+.submission-list small { grid-column: 2; color: var(--muted); font-size: 12px; }
+.submission-list p { grid-column: 1/-1; margin: 3px 0 0; font-size: 14px; line-height: 1.65; }
+.submission-actions { grid-column: 1/-1; display: flex; gap: 8px; justify-content: flex-end; border-top: 1px dashed var(--line); padding-top: 9px; }
+.submission-actions button { border: 1px solid rgba(23,32,29,.2); border-radius: 9px; background: transparent; color: var(--muted); padding: 8px 10px; font-size: 11px; font-weight: 900; cursor: pointer; }
+.submission-actions button.confirm-delete { border-color: #a43f29; background: #a43f29; color: #fff; }
+.policy-confirm { display: flex; flex-direction: column; gap: 8px; border-radius: 14px; background: rgba(122,176,198,.12); padding: 13px; }
+.policy-confirm > label { display: grid; grid-template-columns: 20px 1fr; gap: 8px; align-items: start; color: var(--ink); font-size: 12px; line-height: 1.6; }
+.policy-confirm input { width: 17px; height: 17px; margin-top: 2px; accent-color: var(--ink); }
+.policy-confirm a { color: #397386; text-decoration: underline; font-weight: 900; }
+.policy-accepted { margin: 0; border-radius: 999px; background: rgba(217,240,93,.28); color: #5c6e10; padding: 8px 11px; font-size: 11px; font-weight: 900; }
+.story-status { width: fit-content; padding: 4px 7px; background: #ded8c9; font-size: 11px; font-weight: 900; }
+.status-published { background: var(--acid); }
+.status-review { background: #ffd69f; }
+.community-message { position: sticky; bottom: 0; margin: 12px 0 0; border: 1px solid var(--ink); background: var(--acid); color: var(--ink); padding: 10px 12px; font-size: 13px; line-height: 1.55; font-weight: 800; }
+
+.admin-shade { z-index: 82; }
+.admin-community-panel { width: min(960px, 100%); max-height: min(920px, calc(100vh - 32px)); overflow-y: auto; position: relative; border: 1px solid rgba(23,32,29,.24); border-radius: 25px; background: #f7f4ea; color: var(--ink); padding: 30px; box-shadow: 0 28px 80px rgba(7,14,12,.36), 8px 8px 0 rgba(122,176,198,.9); }
+.admin-community-head { display: flex; align-items: center; gap: 15px; padding-right: 42px; }
+.admin-community-head > span { width: 54px; height: 54px; flex: 0 0 auto; display: grid; place-items: center; border-radius: 18px; background: var(--ink); color: #a9dce9; font-size: 24px; box-shadow: 0 8px 20px rgba(23,32,29,.18); }
+.admin-community-head p { margin: 0 0 3px; color: #397386; font: 900 12px var(--font-mono); letter-spacing: .08em; }
+.admin-community-head h2 { margin: 0 0 5px; font-size: 28px; letter-spacing: -.03em; }
+.admin-community-head small { color: var(--muted); font-size: 13px; line-height: 1.55; }
+.admin-count-grid { display: grid; grid-template-columns: repeat(4,1fr); gap: 10px; margin: 20px 0 14px; }
+.admin-count-grid button { min-height: 80px; display: flex; flex-direction: column; align-items: flex-start; justify-content: center; gap: 2px; border: 1px solid rgba(23,32,29,.14); border-radius: 16px; background: #fff; color: var(--ink); padding: 12px 15px; cursor: pointer; box-shadow: 0 6px 16px rgba(23,32,29,.06); }
+.admin-count-grid b { font: 900 26px var(--font-mono); }
+.admin-count-grid span { color: var(--muted); font-size: 12px; font-weight: 900; }
+.admin-tabs { display: grid; grid-template-columns: repeat(3,1fr); gap: 7px; padding: 6px; border-radius: 16px; background: rgba(23,32,29,.07); }
+.admin-tabs button { border: 0; border-radius: 11px; background: transparent; color: var(--muted); min-height: 43px; font-size: 14px; font-weight: 900; cursor: pointer; }
+.admin-tabs button.active { background: var(--ink); color: #fff; box-shadow: 0 5px 13px rgba(23,32,29,.18); }
+.admin-queue, .admin-report-list, .admin-log-list { display: flex; flex-direction: column; gap: 11px; margin-top: 14px; }
+.admin-filters { display: flex; flex-wrap: wrap; gap: 7px; }
+.admin-filters button { border: 1px solid rgba(23,32,29,.15); border-radius: 999px; background: #fff; color: var(--muted); padding: 8px 12px; font-size: 12px; font-weight: 900; cursor: pointer; }
+.admin-filters button.active { border-color: var(--ink); background: var(--ink); color: var(--acid); }
+.admin-empty { min-height: 110px; display: grid; place-items: center; margin: 0; border: 1px dashed rgba(23,32,29,.2); border-radius: 17px; color: var(--muted); font-size: 14px; font-weight: 800; }
+.admin-story { border: 1px solid rgba(23,32,29,.17); border-left: 5px solid #9aa4a1; border-radius: 17px; background: #fff; padding: 16px; box-shadow: 0 8px 22px rgba(23,32,29,.06); }
+.admin-story.status-pending { border-left-color: #e6b755; }
+.admin-story.status-review { border-left-color: var(--coral); }
+.admin-story.status-hidden, .admin-story.status-rejected { opacity: .8; }
+.admin-story-meta { display: grid; grid-template-columns: 35px 1fr auto; gap: 10px; align-items: center; }
+.admin-story-meta > span { font-size: 25px; }
+.admin-story-meta > div { display: flex; flex-direction: column; gap: 3px; }
+.admin-story-meta strong { font-size: 15px; }
+.admin-story-meta small { color: var(--muted); font-size: 12px; }
+.admin-story-meta > i { border-radius: 999px; background: rgba(23,32,29,.08); color: var(--muted); padding: 6px 9px; font: normal 900 11px var(--font-mono); }
+.admin-story > p { margin: 14px 0; font-size: 15px; line-height: 1.75; }
+.admin-story-signals { display: flex; flex-wrap: wrap; gap: 8px; }
+.admin-story-signals span { border-radius: 999px; background: rgba(217,240,93,.22); padding: 6px 9px; font-size: 12px; font-weight: 900; }
+.admin-story-signals span.danger { background: rgba(232,110,78,.15); color: #a43f29; }
+.admin-story-actions { display: flex; flex-wrap: wrap; gap: 8px; margin-top: 13px; }
+.admin-story-actions button, .admin-decision button, .admin-report-list button { min-height: 41px; border: 1px solid rgba(23,32,29,.24); border-radius: 11px; background: #fff; color: var(--ink); padding: 9px 12px; font-size: 12px; font-weight: 900; cursor: pointer; }
+.admin-story-actions button.approve { border-color: var(--ink); background: var(--ink); color: var(--acid); }
+.admin-story-actions button.danger { color: #a43f29; border-color: rgba(164,63,41,.34); }
+.admin-story-actions button:disabled { opacity: .45; cursor: default; }
+.admin-decision { margin-top: 13px; border-radius: 13px; background: rgba(232,110,78,.08); padding: 13px; }
+.admin-decision label { display: flex; flex-direction: column; gap: 7px; color: var(--muted); font-size: 12px; font-weight: 900; }
+.admin-decision textarea { min-height: 76px; resize: vertical; border: 1px solid rgba(23,32,29,.28); border-radius: 10px; background: #fff; color: var(--ink); padding: 10px; font-size: 14px; }
+.admin-decision > div { display: flex; justify-content: flex-end; gap: 8px; margin-top: 9px; }
+.admin-decision > div button:last-child { background: var(--ink); color: #fff; }
+.admin-decision > div button:disabled { opacity: .42; }
+.admin-report-list article { border: 1px solid rgba(164,63,41,.22); border-radius: 16px; background: #fff7f4; padding: 15px; }
+.admin-report-list article > div { display: flex; justify-content: space-between; gap: 10px; }
+.admin-report-list strong { color: #a43f29; font-size: 14px; }
+.admin-report-list i { color: var(--muted); font-size: 11px; font-style: normal; font-weight: 900; }
+.admin-report-list span, .admin-report-list p { color: var(--muted); font-size: 12px; line-height: 1.6; }
+.admin-report-list button { border: 0; background: transparent; color: #397386; padding-left: 0; }
+.admin-log-list article { display: grid; grid-template-columns: 160px 180px 1fr; gap: 12px; align-items: center; border-bottom: 1px solid rgba(23,32,29,.12); padding: 11px 4px; }
+.admin-log-list b { font-size: 13px; }
+.admin-log-list span { font: 800 11px var(--font-mono); }
+.admin-log-list small { color: var(--muted); font-size: 12px; }
+.admin-message { position: sticky; bottom: 0; margin: 14px 0 0; border-radius: 12px; background: var(--ink); color: #fff; padding: 11px 13px; font-size: 13px; font-weight: 800; }
+
+/* Invite-only beta feedback and operator controls */
+.feedback-shade { z-index: 86; }
+.feedback-panel { width: min(650px,100%); max-height: min(880px,calc(100vh - 32px)); overflow-y: auto; position: relative; border: 1px solid rgba(23,32,29,.22); border-radius: 24px; background: #f7f4ea; color: var(--ink); padding: 31px; box-shadow: 0 27px 75px rgba(7,14,12,.34), 8px 8px 0 rgba(217,240,93,.82); }
+.feedback-panel h2 { margin: 8px 0 9px; font-size: 30px; letter-spacing: -.04em; }
+.feedback-panel > p:not(.detail-kicker):not(.feedback-status) { margin: 0 0 18px; color: var(--muted); font-size: 14px; line-height: 1.7; }
+.feedback-panel form { display: flex; flex-direction: column; gap: 14px; }
+.feedback-panel form > label { display: flex; flex-direction: column; gap: 7px; color: var(--muted); font-size: 13px; font-weight: 900; }
+.feedback-panel select, .feedback-panel textarea { width: 100%; border: 1px solid rgba(23,32,29,.3); border-radius: 12px; background: #fff; color: var(--ink); padding: 11px 12px; font-size: 15px; outline: none; }
+.feedback-panel textarea { min-height: 145px; resize: vertical; line-height: 1.6; }
+.feedback-panel form > label > small { text-align: right; font: 800 11px var(--font-mono); }
+.feedback-panel fieldset { margin: 0; border: 1px solid rgba(23,32,29,.16); border-radius: 14px; background: rgba(255,255,255,.55); padding: 12px; }
+.feedback-panel legend { padding: 0 6px; color: var(--muted); font-size: 13px; font-weight: 900; }
+.feedback-rating { display: grid; grid-template-columns: repeat(5,1fr); gap: 6px; }
+.feedback-rating button { min-height: 48px; display: flex; flex-direction: column; align-items: center; justify-content: center; gap: 1px; border: 1px solid rgba(23,32,29,.18); border-radius: 10px; background: #fff; color: var(--ink); font: 900 15px var(--font-mono); cursor: pointer; }
+.feedback-rating button small { min-height: 12px; font: 800 9px system-ui,sans-serif; }
+.feedback-rating button.active { border-color: var(--ink); background: var(--ink); color: var(--acid); }
+.feedback-submit { min-height: 48px; border: 1px solid var(--ink); border-radius: 13px; background: var(--ink); color: #fff; font-size: 14px; font-weight: 900; cursor: pointer; box-shadow: 4px 4px 0 var(--acid); }
+.feedback-submit:disabled { opacity: .45; cursor: default; box-shadow: none; }
+.feedback-status { margin: 14px 0 0; border-left: 4px solid #6b8a24; border-radius: 8px; background: rgba(217,240,93,.2); padding: 11px 12px; font-size: 13px; font-weight: 800; line-height: 1.55; }
+.feedback-vault-needed { display: flex; flex-direction: column; gap: 8px; border: 1px solid rgba(23,32,29,.18); border-radius: 17px; background: rgba(122,176,198,.12); padding: 18px; }
+.feedback-vault-needed strong { font-size: 17px; }
+.feedback-vault-needed span { color: var(--muted); font-size: 13px; line-height: 1.6; }
+.feedback-vault-needed button { min-height: 43px; border: 1px solid var(--ink); border-radius: 11px; background: var(--ink); color: #fff; font-size: 13px; font-weight: 900; cursor: pointer; }
+.beta-admin-shade { z-index: 88; }
+.beta-admin-panel { width: min(920px,100%); max-height: min(900px,calc(100vh - 32px)); overflow-y: auto; position: relative; border: 1px solid rgba(23,32,29,.22); border-radius: 25px; background: #f7f4ea; color: var(--ink); padding: 30px; box-shadow: 0 28px 80px rgba(7,14,12,.36), 8px 8px 0 rgba(217,240,93,.82); }
+.beta-admin-panel > header { display: flex; align-items: center; gap: 14px; padding-right: 42px; }
+.beta-admin-panel > header > span { width: 54px; height: 54px; flex: 0 0 auto; display: grid; place-items: center; border-radius: 17px; background: var(--ink); color: var(--acid); font: 900 22px var(--font-mono); }
+.beta-admin-panel > header p { margin: 0 0 3px; color: #637816; font: 900 11px var(--font-mono); letter-spacing: .1em; }
+.beta-admin-panel > header h2 { margin: 0 0 5px; font-size: 28px; letter-spacing: -.035em; }
+.beta-admin-panel > header small { color: var(--muted); font-size: 13px; line-height: 1.55; }
+.beta-admin-counts { display: grid; grid-template-columns: repeat(4,1fr); gap: 9px; margin: 20px 0 13px; }
+.beta-admin-counts > div { min-height: 86px; display: flex; flex-direction: column; justify-content: center; gap: 4px; border: 1px solid rgba(23,32,29,.15); border-radius: 16px; background: #fff; padding: 13px 15px; }
+.beta-admin-counts b { font: 900 25px var(--font-mono); }
+.beta-admin-counts span { color: var(--muted); font-size: 11px; font-weight: 900; }
+.beta-signup-control { display: grid; grid-template-columns: 1fr auto; align-items: center; gap: 13px; border-radius: 17px; padding: 15px; }
+.beta-signup-control.enabled { border: 1px solid rgba(100,118,17,.25); background: rgba(217,240,93,.2); }
+.beta-signup-control.paused { border: 1px solid rgba(164,63,41,.25); background: rgba(232,110,78,.1); }
+.beta-signup-control > div { display: flex; flex-direction: column; gap: 4px; }
+.beta-signup-control strong { font-size: 15px; }
+.beta-signup-control span { color: var(--muted); font-size: 12px; }
+.beta-signup-control button { min-height: 42px; border: 1px solid var(--ink); border-radius: 11px; background: var(--ink); color: #fff; padding: 9px 13px; font-size: 12px; font-weight: 900; cursor: pointer; }
+.beta-feedback-queue { margin-top: 15px; }
+.beta-feedback-queue > div { display: flex; align-items: center; justify-content: space-between; border-bottom: 1px solid rgba(23,32,29,.2); padding-bottom: 10px; }
+.beta-feedback-queue > div strong { font-size: 16px; }
+.beta-feedback-queue > div button { border: 0; background: transparent; color: #397386; font-size: 12px; font-weight: 900; cursor: pointer; }
+.beta-feedback-queue > p, .beta-admin-empty { min-height: 100px; display: grid; place-items: center; color: var(--muted); font-size: 14px; }
+.beta-feedback-queue article { display: grid; grid-template-columns: 1fr auto; gap: 7px 12px; border-bottom: 1px solid rgba(23,32,29,.13); padding: 13px 3px; }
+.beta-feedback-queue article.resolved { opacity: .58; }
+.beta-feedback-queue article header { grid-column: 1/-1; display: flex; justify-content: space-between; gap: 10px; }
+.beta-feedback-queue article header b { color: #788d19; font-size: 14px; letter-spacing: .05em; }
+.beta-feedback-queue article header span, .beta-feedback-queue article small { color: var(--muted); font-size: 11px; }
+.beta-feedback-queue article p { grid-column: 1/-1; margin: 0; font-size: 14px; line-height: 1.65; }
+.beta-feedback-queue article button { border: 1px solid rgba(23,32,29,.23); border-radius: 9px; background: #fff; color: var(--ink); padding: 7px 10px; font-size: 11px; font-weight: 900; cursor: pointer; }
+.beta-feedback-queue article em { color: #637816; font-size: 11px; font-style: normal; font-weight: 900; }
+
+/* Safety center and public-readiness rules */
+.safety-page { min-height: 100vh; background: #f2eee3; color: var(--ink); padding: 0 max(22px, calc((100vw - 1180px) / 2)) 50px; }
+.safety-nav { min-height: 76px; display: flex; align-items: center; justify-content: space-between; gap: 20px; border-bottom: 1px solid rgba(23,32,29,.2); }
+.safety-nav > a { font-size: 14px; font-weight: 900; }
+.safety-nav > div { display: flex; align-items: center; gap: 14px; }
+.safety-nav span { color: var(--muted); font: 800 10px var(--font-mono); letter-spacing: .06em; }
+.safety-nav div a { border: 1px solid var(--ink); border-radius: 999px; padding: 7px 11px; font-size: 12px; font-weight: 900; }
+.safety-hero { padding: 78px 0 40px; }
+.safety-hero > p, .safety-sources > div > p { margin: 0 0 14px; color: #637816; font: 900 12px var(--font-mono); letter-spacing: .13em; }
+.safety-hero h1 { max-width: 900px; margin: 0 0 20px; font-size: clamp(42px, 7vw, 82px); line-height: .98; letter-spacing: -.065em; }
+.safety-hero > span { display: block; max-width: 760px; color: var(--muted); font-size: 18px; line-height: 1.75; }
+.safety-hero-note { max-width: 880px; display: flex; gap: 12px; align-items: flex-start; margin-top: 28px; border: 1px solid rgba(23,32,29,.18); border-radius: 16px; background: rgba(255,255,255,.56); padding: 14px 16px; }
+.safety-hero-note b { width: 27px; height: 27px; flex: 0 0 auto; display: grid; place-items: center; border-radius: 50%; background: var(--coral); color: #fff; }
+.safety-hero-note p { margin: 1px 0 0; color: var(--muted); font-size: 13px; line-height: 1.65; }
+.safety-principles { display: grid; grid-template-columns: repeat(3,1fr); gap: 12px; margin-bottom: 66px; }
+.safety-principles article { min-height: 200px; display: flex; flex-direction: column; align-items: flex-start; border-radius: 21px; background: var(--ink); color: #fff; padding: 23px; box-shadow: 0 14px 34px rgba(23,32,29,.13); }
+.safety-principles article:nth-child(2) { background: #4f7885; }
+.safety-principles article:nth-child(3) { background: #647611; }
+.safety-principles b { width: 41px; height: 41px; display: grid; place-items: center; margin-bottom: auto; border-radius: 14px; background: rgba(255,255,255,.12); color: var(--acid); font-size: 19px; }
+.safety-principles strong { margin: 24px 0 7px; font-size: 19px; }
+.safety-principles span { color: rgba(255,255,255,.73); font-size: 13px; line-height: 1.65; }
+.safety-section { border-top: 1px solid rgba(23,32,29,.24); padding: 52px 0 68px; }
+.safety-section-title { display: flex; align-items: center; gap: 18px; margin-bottom: 26px; }
+.safety-section-title > span { width: 52px; height: 52px; display: grid; place-items: center; border-radius: 50%; background: var(--ink); color: var(--acid); font: 900 13px var(--font-mono); }
+.safety-section-title p { margin: 0 0 3px; color: var(--muted); font: 900 10px var(--font-mono); letter-spacing: .1em; }
+.safety-section-title h2 { margin: 0; font-size: clamp(27px,4vw,42px); letter-spacing: -.04em; }
+.data-layer-grid { display: grid; grid-template-columns: repeat(3,1fr); gap: 11px; }
+.data-layer-grid article { border: 1px solid rgba(23,32,29,.18); border-radius: 19px; background: rgba(255,255,255,.66); padding: 20px; }
+.data-layer-grid em { width: 31px; height: 31px; display: grid; place-items: center; border-radius: 10px; background: var(--acid); font: normal 900 12px var(--font-mono); }
+.data-layer-grid h3 { margin: 22px 0 7px; font-size: 18px; }
+.data-layer-grid p, .safety-detail-grid li, .rule-columns li { color: var(--muted); font-size: 13px; line-height: 1.7; }
+.safety-detail-grid { display: grid; grid-template-columns: repeat(2,1fr); gap: 11px; margin-top: 11px; }
+.safety-detail-grid article { border-radius: 19px; background: #fff; padding: 21px 23px; }
+.safety-detail-grid h3 { margin: 0 0 12px; font-size: 17px; }
+.safety-detail-grid ul, .rule-columns ul { margin: 0; padding-left: 19px; }
+.safety-detail-grid li + li, .rule-columns li + li { margin-top: 7px; }
+.rule-columns { display: grid; grid-template-columns: 1fr 1fr; gap: 12px; }
+.rule-columns article { border-radius: 21px; padding: 24px; }
+.rule-columns h3 { margin: 0 0 14px; font-size: 20px; }
+.rule-allowed { background: rgba(217,240,93,.22); border: 1px solid rgba(100,118,17,.25); }
+.rule-blocked { background: rgba(232,110,78,.1); border: 1px solid rgba(164,63,41,.2); }
+.rule-blocked h3 { color: #a43f29; }
+.moderation-flow { display: grid; grid-template-columns: repeat(4,1fr); gap: 9px; margin-top: 12px; }
+.moderation-flow article { min-height: 150px; display: flex; flex-direction: column; gap: 18px; border-radius: 17px; background: var(--ink); color: #fff; padding: 17px; }
+.moderation-flow b { width: 29px; height: 29px; display: grid; place-items: center; border-radius: 50%; background: var(--acid); color: var(--ink); font: 900 11px var(--font-mono); }
+.moderation-flow span { color: rgba(255,255,255,.74); font-size: 12px; line-height: 1.65; }
+.boundary-panel { border-radius: 22px; background: #fff; padding: 27px; }
+.boundary-panel h3 { margin: 0 0 8px; font-size: 18px; }
+.boundary-panel h3:not(:first-child) { margin-top: 24px; }
+.boundary-panel p { max-width: 940px; margin: 0; color: var(--muted); font-size: 14px; line-height: 1.8; }
+.urgent-panel { display: flex; gap: 18px; align-items: flex-start; margin-top: 12px; border-radius: 22px; background: #4e2521; color: #fff; padding: 24px; }
+.urgent-panel > b { width: 62px; height: 62px; flex: 0 0 auto; display: grid; place-items: center; border: 2px solid var(--coral); border-radius: 50%; color: #ffd2c7; font: 900 15px var(--font-mono); }
+.urgent-panel h3 { margin: 3px 0 7px; font-size: 18px; }
+.urgent-panel p { margin: 0; color: rgba(255,255,255,.75); font-size: 13px; line-height: 1.7; }
+.control-steps { margin: 0; padding: 0; display: grid; grid-template-columns: repeat(3,1fr); gap: 11px; list-style: none; }
+.control-steps li { display: flex; gap: 13px; border-radius: 18px; background: #fff; padding: 19px; }
+.control-steps li > b { width: 31px; height: 31px; flex: 0 0 auto; display: grid; place-items: center; border-radius: 10px; background: var(--ink); color: var(--acid); font: 900 11px var(--font-mono); }
+.control-steps div { display: flex; flex-direction: column; gap: 6px; }
+.control-steps strong { font-size: 15px; }
+.control-steps span { color: var(--muted); font-size: 12px; line-height: 1.65; }
+.anonymous-rights-note { margin: 13px 0 0; border: 1px dashed rgba(23,32,29,.3); border-radius: 15px; color: var(--muted); padding: 14px 16px; font-size: 12px; line-height: 1.7; }
+.safety-sources { display: grid; grid-template-columns: 1.1fr 1fr; gap: 30px; align-items: start; border-radius: 24px; background: var(--ink); color: #fff; padding: 30px; }
+.safety-sources h2 { margin: 0 0 10px; font-size: 28px; }
+.safety-sources > div > span { color: rgba(255,255,255,.65); font-size: 12px; line-height: 1.7; }
+.safety-sources nav { display: flex; flex-direction: column; }
+.safety-sources nav a { border-bottom: 1px solid rgba(255,255,255,.14); color: rgba(255,255,255,.84); padding: 10px 3px; font-size: 13px; font-weight: 800; }
+.safety-sources nav a:hover { color: var(--acid); }
+.safety-footer { display: flex; align-items: center; justify-content: space-between; gap: 18px; padding: 35px 2px 0; }
+.safety-footer strong { font-size: 14px; }
+.safety-footer span { color: var(--muted); font-size: 11px; }
+.safety-footer a { font-size: 13px; font-weight: 900; }
+.privacy-meter { border: 1px solid var(--ink); background: #fff; padding: 15px; }
+.privacy-meter > div { display: flex; align-items: baseline; justify-content: space-between; gap: 10px; }
+.privacy-meter strong { font: 900 22px var(--font-mono); }
+.privacy-meter span { color: var(--muted); font-size: 13px; }
+.privacy-meter > i { display: block; height: 10px; margin-top: 10px; background: #d8d2c6; overflow: hidden; }
+.privacy-meter > i > b { display: block; height: 100%; background: linear-gradient(90deg,var(--coral),var(--acid)); }
+.insight-lock { border: 1px dashed var(--ink); padding: 22px; }
+.insight-lock > strong { font-size: 18px; }
+.insight-lock > p { color: var(--muted); font-size: 14px; line-height: 1.7; }
+.insight-lock > small { display: block; color: var(--muted); font-size: 12px; margin-top: 12px; }
+.demo-insights { display: grid; grid-template-columns: repeat(3,1fr); gap: 9px; }
+.demo-insights article { min-height: 95px; border: 1px solid var(--line); background: rgba(122,176,198,.11); padding: 13px; display: flex; flex-direction: column; justify-content: center; }
+.demo-insights b { font: 900 26px var(--font-mono); }
+.demo-insights span { color: var(--muted); font-size: 12px; line-height: 1.5; }
+.aggregate-grid { display: grid; grid-template-columns: 1fr 1fr; gap: 12px; }
+.aggregate-grid section { border: 1px solid var(--ink); background: #fff; padding: 15px; }
+.aggregate-grid h3 { margin: 0 0 13px; font-size: 16px; }
+.aggregate-row { display: grid; grid-template-columns: minmax(120px,1fr) 1fr 30px; gap: 8px; align-items: center; margin-top: 9px; }
+.aggregate-row span { font-size: 12px; }
+.aggregate-row > i { height: 8px; background: #ded8c9; overflow: hidden; }
+.aggregate-row > i > b { display: block; height: 100%; background: var(--coral); }
+.aggregate-row strong { text-align: right; font: 800 12px var(--font-mono); }
+
+@media (max-width: 980px) {
+ .top-actions > .community-open { max-width: 110px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
+}
+
+@media (max-width: 720px) {
+ .community-panel { width: calc(100vw - 18px); max-height: calc(100vh - 18px); padding: 27px 18px; }
+ .admin-community-panel { width: calc(100vw - 18px); max-height: calc(100vh - 18px); padding: 25px 16px; border-radius: 19px; }
+ .feedback-panel, .beta-admin-panel { width: calc(100vw - 18px); max-height: calc(100vh - 18px); padding: 25px 17px; border-radius: 19px; }
+ .beta-admin-panel > header > span { display: none; }
+ .beta-admin-panel > header h2, .feedback-panel h2 { font-size: 24px; }
+ .beta-admin-counts { grid-template-columns: repeat(2,1fr); }
+ .beta-signup-control { grid-template-columns: 1fr; }
+ .admin-community-head > span { display: none; }
+ .admin-community-head h2 { font-size: 23px; }
+ .admin-count-grid { grid-template-columns: repeat(2,1fr); }
+ .admin-story-meta { grid-template-columns: 32px 1fr; }
+ .admin-story-meta > i { grid-column: 2; width: fit-content; }
+ .admin-log-list article { grid-template-columns: 1fr; gap: 4px; }
+ .safety-page { padding-inline: 14px; }
+ .safety-nav { min-height: 64px; }
+ .safety-nav span { display: none; }
+ .safety-hero { padding-top: 54px; }
+ .safety-hero h1 { font-size: 43px; }
+ .safety-hero > span { font-size: 16px; }
+ .safety-principles, .data-layer-grid, .safety-detail-grid, .rule-columns, .moderation-flow, .control-steps, .safety-sources { grid-template-columns: 1fr; }
+ .safety-principles article { min-height: 175px; }
+ .safety-section { padding: 42px 0 52px; }
+ .safety-section-title > span { width: 43px; height: 43px; }
+ .urgent-panel { flex-direction: column; }
+ .safety-footer { align-items: flex-start; flex-direction: column; }
+ .community-head h2 { font-size: 22px; }
+ .aggregate-grid { grid-template-columns: 1fr; }
+ .advisor-prompts { grid-template-columns: 1fr; }
+ .guide-controls { max-height: 55vh; }
+}
+
+@media (max-width: 430px) {
+ .top-actions > .community-open { display: none; }
+ .top-actions > .safety-link { display: none; }
+ .top-actions > .feedback-open { padding-inline: 11px; }
+ .community-head > span { display: none; }
+ .community-head { padding-right: 34px; }
+ .community-tabs button { font-size: 12px; padding: 7px 3px; }
+ .demo-insights { grid-template-columns: 1fr; }
+ .story-meta { grid-template-columns: 32px 1fr; }
+ .story-meta time { grid-column: 2; }
+ .community-story footer { flex-direction: column; }
+ .special-tabs, .advisor-form > div { grid-template-columns: 1fr; }
+ .real-world-empty { right: 8px; top: 74px; width: 198px; }
+ .real-story-actions { grid-template-columns: 1fr; }
+ .real-light-milestones > div:first-child { align-items: flex-start; flex-direction: column; }
+}
+
+/* Final specificity overrides for the zoomed self marker. */
+.player .player-name { top: 94px; z-index: 12; min-width: 126px; display: grid; grid-template-columns: 1fr auto; gap: 3px 7px; align-items: center; padding: 7px 10px; border-radius: 12px; background: rgba(255,248,232,.97); text-align: left; }
+
+/* Shared-world readability: keep lift effects beside walkers and protect every data card. */
+.npc .npc-tag {
+ z-index: 20;
+ min-width: 190px;
+ margin-bottom: 12px;
+ padding: 13px 15px;
+ border-radius: 19px;
+ gap: 5px 10px;
+}
+.npc .npc-tag-label { font-size: 11px; line-height: 1.35; }
+.npc .npc-tag strong { font-size: 18px; line-height: 1.2; }
+.npc .npc-tag b,
+.npc .npc-tag i { font-size: 12px; line-height: 1.35; }
+.npc small.npc-name {
+ position: relative;
+ z-index: 10;
+ gap: 8px;
+ margin-top: 7px;
+ padding: 6px 11px;
+ font-size: 13px;
+ line-height: 1.25;
+}
+.npc .npc-name b { font-size: 11px; }
+.npc > em { z-index: 24; padding: 7px 11px; font-size: 12px; }
+.npc .npc-character { z-index: 6; }
+.npc > .burden-lift {
+ z-index: 3;
+ left: calc(50% + 58px);
+ bottom: 2px;
+ transform: translateX(-50%) scale(.86);
+}
+.npc > .burden-lift.lift-tier-4 { transform: translateX(-50%) scale(.94); }
+
+.player .player-total-debt { z-index: 24; min-width: 248px; padding: 14px 16px; }
+.player .player-total-debt small { font-size: 11px; }
+.player .player-total-debt strong { font-size: 23px; }
+.player .player-total-debt > span,
+.player .player-total-debt > i { padding: 4px 7px; font-size: 11px; }
+.player > .burden-lift {
+ z-index: 3;
+ left: calc(50% + 70px);
+ bottom: 5px;
+ transform: translateX(-50%) scale(.84);
+}
+.player > .burden-lift.lift-tier-4 { transform: translateX(-50%) scale(.92); }
+.player .player-avatar { z-index: 9; }
+.player .player-name {
+ z-index: 16;
+ min-width: 150px;
+ padding: 8px 11px;
+ font-size: 13px;
+}
+.player .player-name b { font-size: 10px; }
+.player-self-marker { z-index: 18; padding: 6px 10px; font-size: 11px; }
+
+.orbit-label { min-width: 148px; padding: 11px 13px; gap: 5px 9px; }
+.orbit-label span { font-size: 13px; line-height: 1.35; }
+.orbit-label strong { font-size: 15px; }
+.orbit-label i { width: 28px; height: 28px; font-size: 10px; }
+.orbit-more-label { min-width: 148px; padding: 10px 13px; font-size: 12px; }
+
+.district { width: 130px; height: 88px; }
+.district span { font-size: 24px; }
+.district strong { font-size: 12px; line-height: 1.3; }
+.district small { padding: 3px 8px; font-size: 10px; }
+.world-growth-status { padding: 10px 16px; }
+.world-growth-status b { font-size: 11px; }
+.world-growth-status span { font-size: 12px; }
+.world-message { max-width: 330px; }
+.world-message p { font-size: 15px; }
+
+/* A larger canvas is unlocked by visible role count; the stage stays pannable like a map. */
+.world-canvas.world-expansion-1 { left: -34%; top: -34%; width: 168%; height: 168%; }
+.world-canvas.world-expansion-2 { left: -46%; top: -46%; width: 192%; height: 192%; }
+.world-canvas.world-expansion-3 { left: -61%; top: -61%; width: 222%; height: 222%; }
+.demo-world-note {
+ position: absolute;
+ z-index: 34;
+ top: 62px;
+ right: 14px;
+ width: min(268px, calc(100% - 28px));
+ display: grid;
+ gap: 3px;
+ padding: 10px 12px;
+ border: 1px dashed rgba(255,255,255,.42);
+ border-radius: 14px;
+ color: #fff;
+ background: rgba(29,42,38,.9);
+ box-shadow: 0 10px 28px rgba(23,32,29,.2);
+ backdrop-filter: blur(9px);
+ pointer-events: none;
+}
+.demo-world-note b { color: #ffd58c; font: 900 11px var(--font-mono); letter-spacing: .04em; }
+.demo-world-note span { color: rgba(255,255,255,.78); font-size: 11px; font-weight: 800; line-height: 1.4; }
+.demo-world-note i { color: var(--blue); font: 800 9px var(--font-mono); font-style: normal; }
+
+/* Demo labels stay quiet until inspected so a 30-person world remains readable. */
+.demo-npc .npc-tag {
+ visibility: hidden;
+ opacity: 0;
+ transform: translateY(7px) scale(.94);
+ pointer-events: none;
+ transition: opacity .16s ease, visibility .16s ease, transform .16s ease, box-shadow .18s ease;
+}
+.demo-npc:hover .npc-tag,
+.demo-npc.npc-near .npc-tag {
+ visibility: visible;
+ opacity: 1;
+ transform: translateY(-2px) scale(1);
+}
+.demo-npc .npc-tag { border-style: dashed; border-color: rgba(255,211,138,.48); }
+.demo-npc .npc-tag::before { background: linear-gradient(90deg,transparent,#ffd58c,var(--blue),transparent); }
+.demo-npc .npc-tag-label { color: #ffd58c; }
+.demo-npc small.npc-name { border-style: dashed; border-color: rgba(155,120,60,.34); background: rgba(255,248,232,.94); }
+.demo-data-notice {
+ margin: 14px 0 0;
+ padding: 12px 14px;
+ border: 1px dashed #c89955;
+ border-radius: 13px;
+ color: #76552f;
+ background: #fff5de;
+ font-size: 12px;
+ font-weight: 800;
+ line-height: 1.6;
+}
+
+/* Living map: time-of-day atmosphere, biomes, task routes, and a useful map lens. */
+.world-stage { isolation: isolate; transition: background .5s ease; }
+.world-stage.world-dawn { background: radial-gradient(circle at 72% 24%,rgba(255,193,141,.33),transparent 24%),radial-gradient(circle at 20% 75%,rgba(126,182,202,.25),transparent 25%),linear-gradient(145deg,#ead8c8,#c7d3cb); }
+.world-stage.world-day { background: radial-gradient(circle at 74% 28%,rgba(217,240,93,.24),transparent 22%),radial-gradient(circle at 22% 72%,rgba(126,182,202,.28),transparent 25%),linear-gradient(140deg,#ebe5d2,#cbd3c3); }
+.world-stage.world-dusk { background: radial-gradient(circle at 78% 20%,rgba(238,141,102,.4),transparent 27%),radial-gradient(circle at 20% 75%,rgba(130,147,190,.3),transparent 28%),linear-gradient(145deg,#d9c6b7,#adb9b5); }
+.world-stage.world-night { background: radial-gradient(circle at 76% 20%,rgba(217,240,93,.12),transparent 20%),radial-gradient(circle at 20% 72%,rgba(126,182,202,.22),transparent 24%),linear-gradient(145deg,#70817d,#2d4948); }
+.world-sky { position: absolute; z-index: 2; inset: 0; overflow: hidden; pointer-events: none; opacity: .7; }
+.world-sky > i { position: absolute; width: 86px; height: 24px; border-radius: 999px; background: rgba(255,255,255,.36); box-shadow: 24px 4px 0 -5px rgba(255,255,255,.31),-23px 7px 0 -8px rgba(255,255,255,.29); filter: blur(.3px); animation: map-cloud-drift 28s linear infinite; }
+.world-sky > i:nth-child(1) { left: 6%; top: 14%; animation-delay: -6s; }
+.world-sky > i:nth-child(2) { left: 43%; top: 21%; transform: scale(.7); animation-delay: -19s; }
+.world-sky > i:nth-child(3) { left: 78%; top: 43%; transform: scale(.86); animation-delay: -12s; }
+.world-sky > i:nth-child(4) { left: 23%; top: 68%; transform: scale(.62); animation-delay: -23s; }
+.world-sky > span { position: absolute; display: none; color: #f5ffd0; text-shadow: 0 0 10px #d9f05d; animation: light-twinkle 2.2s ease-in-out infinite; }
+.world-night .world-sky > span,.world-dusk .world-sky > span { display: block; }
+.world-sky > span:nth-of-type(1) { left: 19%; top: 16%; }.world-sky > span:nth-of-type(2) { left: 65%; top: 12%; animation-delay: -.7s; }.world-sky > span:nth-of-type(3) { left: 87%; top: 72%; animation-delay: -1.4s; }
+.map-layer-switcher { position: absolute; z-index: 36; left: 14px; top: 74px; display: flex; align-items: center; gap: 5px; padding: 6px; border: 1px solid rgba(255,255,255,.52); border-radius: 15px; color: #fff; background: rgba(25,38,34,.88); box-shadow: 0 10px 28px rgba(23,32,29,.2); backdrop-filter: blur(10px); }
+.map-layer-switcher b { padding: 0 7px; color: rgba(255,255,255,.56); font: 900 9px var(--font-mono); letter-spacing: .08em; }
+.map-layer-switcher button { min-height: 33px; border: 0; border-radius: 10px; padding: 0 10px; color: rgba(255,255,255,.72); background: rgba(255,255,255,.07); font: 900 10px var(--font-mono); cursor: pointer; }
+.map-layer-switcher button.active { color: var(--ink); background: var(--acid); box-shadow: 0 0 18px rgba(217,240,93,.26); }
+.world-biome,.world-lanterns,.mission-route { position: absolute; pointer-events: none; }
+.biome-lake { z-index: 1; left: 39%; top: 40%; width: 21%; height: 15%; border: 1px solid rgba(35,94,112,.28); border-radius: 49% 42% 51% 46%; background: radial-gradient(ellipse at 42% 34%,rgba(255,255,255,.55),transparent 22%),repeating-radial-gradient(ellipse at center,rgba(117,187,205,.68) 0 4px,rgba(94,163,181,.46) 5px 8px); box-shadow: inset 0 0 22px rgba(255,255,255,.42),0 8px 25px rgba(48,105,120,.18); transform: rotate(-7deg); }
+.biome-lake i { position: absolute; width: 20px; height: 7px; border-radius: 50%; border-top: 2px solid rgba(255,255,255,.72); }.biome-lake i:nth-child(1){left:17%;top:26%;}.biome-lake i:nth-child(2){left:53%;top:57%;}.biome-lake i:nth-child(3){right:9%;top:28%;}
+.biome-grove { z-index: 2; width: 116px; height: 82px; }
+.grove-a { left: 19%; top: 17%; }.grove-b { right: 15%; bottom: 15%; transform: scale(.82); }
+.biome-grove i { position: absolute; width: 29px; height: 36px; border: 1px solid rgba(42,76,44,.25); border-radius: 58% 42% 52% 48%; background: linear-gradient(145deg,#cbe279,#7ba57a); box-shadow: inset -6px -7px rgba(42,83,55,.12),0 5px 10px rgba(35,66,42,.15); }
+.biome-grove i::after { content:""; position:absolute; left:13px; bottom:-13px; width:4px; height:16px; border-radius:3px; background:#7b6046; }
+.biome-grove i:nth-child(1){left:7px;top:28px}.biome-grove i:nth-child(2){left:35px;top:4px;transform:scale(.8)}.biome-grove i:nth-child(3){left:59px;top:31px;transform:scale(1.08)}.biome-grove i:nth-child(4){right:0;top:8px;transform:scale(.7)}.biome-grove i:nth-child(5){left:38px;bottom:0;transform:scale(.65)}
+.world-lanterns { z-index: 3; inset: 0; }
+.world-lanterns i { position:absolute; width:8px; height:8px; border:2px solid rgba(67,82,50,.58); border-radius:50%; background:#fff5a4; box-shadow:0 0 12px #d9f05d,0 0 22px rgba(217,240,93,.46); animation: light-twinkle 2.4s ease-in-out infinite; }
+.world-lanterns i::after { content:""; position:absolute; left:2px; top:8px; width:1px; height:14px; background:rgba(55,71,50,.55); }
+.world-lanterns i:nth-child(1){left:28%;top:41%}.world-lanterns i:nth-child(2){left:43%;top:27%;animation-delay:-.6s}.world-lanterns i:nth-child(3){left:59%;top:63%;animation-delay:-1.2s}.world-lanterns i:nth-child(4){left:73%;top:48%;animation-delay:-1.8s}.world-lanterns i:nth-child(5){left:18%;top:72%;animation-delay:-.9s}.world-lanterns i:nth-child(6){left:84%;top:26%;animation-delay:-1.5s}
+.mission-route { z-index: 2; border: 2px dashed rgba(223,112,76,.42); border-radius: 50%; opacity: .72; transition: opacity .2s ease; }
+.route-a { left: 32%; top: 26%; width: 36%; height: 45%; transform: rotate(7deg); }.route-b { left: 24%; top: 46%; width: 48%; height: 31%; transform: rotate(-9deg); border-color: rgba(104,160,178,.45); }.route-c { left: 43%; top: 19%; width: 23%; height: 58%; transform: rotate(18deg); border-color: rgba(160,183,58,.45); }
+.map-mission { position:absolute; z-index:13; width:56px; height:56px; transform:translate(-50%,-50%); border:0; border-radius:50%; color:var(--ink); background:transparent; cursor:pointer; transition:transform .18s ease,opacity .2s ease,filter .2s ease; }
+.map-mission:hover { transform:translate(-50%,-58%) scale(1.05); z-index:25; }
+.mission-beacon { position:relative; width:52px; height:52px; display:grid; place-items:center; border:2px solid rgba(255,255,255,.8); border-radius:50%; color:#fff; background:linear-gradient(145deg,#de7358,#a94f45); box-shadow:0 8px 22px rgba(137,58,45,.3),0 0 0 8px rgba(232,110,78,.13); }
+.mission-beacon::before,.mission-beacon::after { content:""; position:absolute; inset:-8px; border:1px solid rgba(232,110,78,.4); border-radius:50%; animation:mission-ring 2.4s ease-out infinite; }.mission-beacon::after{animation-delay:-1.2s}
+.mission-beacon i { font:900 13px var(--font-mono); font-style:normal; }.mission-beacon b { position:absolute; right:-4px; top:-5px; width:17px; height:17px; display:grid; place-items:center; border-radius:50%; background:var(--acid); box-shadow:0 0 12px rgba(217,240,93,.7); }.mission-beacon b::after{content:"◆";font-size:7px}
+.mission-soon .mission-beacon { color:var(--ink); background:linear-gradient(145deg,#e8d96b,#b9d24d); }.mission-urgent .mission-beacon { background:linear-gradient(145deg,#f06f55,#923c37); animation:mission-urgent 1.6s ease-in-out infinite; }
+.mission-map-card { position:absolute; left:50%; bottom:64px; width:184px; display:grid; gap:4px; transform:translateX(-50%) translateY(7px); visibility:hidden; opacity:0; padding:11px 13px; border:1px solid rgba(255,255,255,.2); border-radius:15px; color:#fff; background:rgba(22,31,28,.95); box-shadow:0 15px 32px rgba(23,32,29,.26); text-align:left; pointer-events:none; transition:opacity .16s ease,transform .16s ease,visibility .16s ease; }
+.map-mission:hover .mission-map-card,.map-layer-tasks .mission-map-card { visibility:visible; opacity:1; transform:translateX(-50%) translateY(0); }
+.mission-map-card small { color:var(--acid); font:900 9px var(--font-mono); letter-spacing:.06em; }.mission-map-card strong{font-size:14px}.mission-map-card em{color:#bfe5ef;font:800 10px var(--font-mono);font-style:normal}
+.map-layer-tasks .npc,.map-layer-tasks .district { opacity:.2; filter:saturate(.45); }.map-layer-tasks .map-mission{transform:translate(-50%,-50%) scale(1.08)}
+.map-layer-people .map-mission,.map-layer-people .mission-route { opacity:.08; filter:grayscale(1); }.map-layer-people .world-biome{opacity:.45}
+.map-layer-all .npc,.map-layer-all .district,.map-layer-all .map-mission,.map-layer-all .mission-route,.map-layer-people .npc,.map-layer-people .district { transition:opacity .2s ease,filter .2s ease,transform .18s ease; }
+
+/* The dock turns calendar entries into legible missions without pretending payment happened. */
+.world-wrap { grid-template-rows:minmax(0,1fr) 154px; }
+.mission-dock { min-height:154px; grid-template-columns:230px minmax(0,1fr); color:#f7f5ea; border-top:1px solid rgba(255,255,255,.12); background:linear-gradient(100deg,#15211e,#203430 54%,#294843); box-shadow:inset 0 1px rgba(255,255,255,.05); }
+.mission-dock .timeline-title { border-right:1px solid rgba(255,255,255,.13); background:radial-gradient(circle at 20% 30%,rgba(217,240,93,.13),transparent 45%); }
+.mission-dock .timeline-title > span { width:46px; height:46px; display:grid; place-items:center; flex:0 0 auto; border:1px solid rgba(217,240,93,.34); border-radius:15px; color:var(--acid); background:rgba(217,240,93,.08); box-shadow:0 0 24px rgba(217,240,93,.08); }
+.mission-dock .timeline-title strong { color:var(--acid); font-size:12px; }.mission-dock .timeline-title small{color:rgba(255,255,255,.62);font-size:11px;line-height:1.45}
+.mission-dock .timeline-items { padding:10px; gap:8px; scrollbar-color:#688079 transparent; }
+.mission-dock .timeline-items > button { position:relative; flex:1 0 238px; max-width:310px; grid-template-columns:50px minmax(0,1fr) 22px; gap:11px; min-height:130px; padding:12px; overflow:hidden; border:1px solid rgba(255,255,255,.13); border-radius:17px; color:#fff; background:linear-gradient(145deg,rgba(255,255,255,.08),rgba(255,255,255,.035)); box-shadow:inset 0 1px rgba(255,255,255,.06); }
+.mission-dock .timeline-items > button::before { content:""; position:absolute; left:12px; right:12px; top:0; height:2px; background:linear-gradient(90deg,transparent,var(--blue),transparent); }
+.mission-dock .timeline-items > button:hover { color:var(--ink); background:linear-gradient(145deg,#e8f58d,#cfe15d); transform:translateY(-2px); box-shadow:0 10px 24px rgba(3,11,8,.2); }
+.mission-dock .timeline-items > button > span { width:50px; height:64px; align-content:center; gap:2px; border:1px solid rgba(255,255,255,.22); border-radius:14px; background:rgba(255,255,255,.07); }
+.mission-dock .timeline-items > button > span b { font:900 19px var(--font-mono); }.mission-dock .timeline-items > button > span i{color:var(--blue);font:900 8px var(--font-mono);font-style:normal;text-transform:uppercase}
+.mission-dock .timeline-items > button div{gap:5px}.mission-dock .timeline-items em{color:var(--acid);font:900 9px var(--font-mono);font-style:normal;letter-spacing:.05em}.mission-dock .timeline-items strong{font-size:15px}.mission-dock .timeline-items small{color:rgba(255,255,255,.62);font-size:11px}.mission-dock .timeline-items u{color:var(--acid);font-size:20px;text-decoration:none}
+.mission-dock .timeline-items > button:hover em,.mission-dock .timeline-items > button:hover small,.mission-dock .timeline-items > button:hover span i,.mission-dock .timeline-items > button:hover u{color:#35504b}
+.mission-dock .timeline-items > .timeline-soon{border-color:rgba(217,240,93,.4)}.mission-dock .timeline-items > .timeline-urgent{border-color:rgba(238,116,86,.58);box-shadow:inset 0 0 0 1px rgba(238,116,86,.12)}.mission-dock .timeline-items > .timeline-urgent::before{background:linear-gradient(90deg,transparent,var(--coral),transparent)}
+.mission-dock .timeline-items > .mission-empty { max-width:410px; border-style:dashed; }
+
+@keyframes map-cloud-drift { 0%{translate:-30px 0}50%{translate:34px -4px}100%{translate:-30px 0} }
+@keyframes mission-ring { 0%{transform:scale(.75);opacity:.7}100%{transform:scale(1.35);opacity:0} }
+@keyframes mission-urgent { 50%{box-shadow:0 8px 22px rgba(137,58,45,.35),0 0 0 11px rgba(232,110,78,.18)} }
+
+@media (max-width: 760px) {
+ .npc .npc-tag { min-width: 174px; padding: 12px 13px; }
+ .npc .npc-tag strong { font-size: 17px; }
+ .npc > .burden-lift { left: calc(50% + 53px); transform: translateX(-50%) scale(.8); }
+ .npc > .burden-lift.lift-tier-4 { transform: translateX(-50%) scale(.87); }
+ .player .player-total-debt { min-width: 226px; }
+ .player > .burden-lift { left: calc(50% + 62px); transform: translateX(-50%) scale(.78); }
+ .player > .burden-lift.lift-tier-4 { transform: translateX(-50%) scale(.86); }
+ .district { width: 122px; height: 82px; }
+ .district strong { font-size: 11px; }
+ .world-growth-status span { font-size: 11px; }
+ .world-canvas.world-expansion-1 { left: -46%; top: -39%; width: 192%; height: 178%; }
+ .world-canvas.world-expansion-2 { left: -58%; top: -53%; width: 216%; height: 206%; }
+ .world-canvas.world-expansion-3 { left: -72%; top: -68%; width: 244%; height: 236%; }
+ .demo-world-note { top: 68px; right: 8px; width: 216px; padding: 8px 10px; }
+ .demo-world-note span { font-size: 10px; }
+ .map-layer-switcher { left:8px; top:72px; max-width:calc(100% - 240px); }.map-layer-switcher b{display:none}.map-layer-switcher button{padding:0 8px;font-size:9px}
+ .world-wrap { grid-template-rows:580px 154px; }
+ .mission-dock { grid-template-columns:118px minmax(0,1fr); }
+ .mission-dock .timeline-title { padding:10px; gap:7px; }.mission-dock .timeline-title > span{width:34px;height:34px;border-radius:11px}.mission-dock .timeline-title small{font-size:9px}.mission-dock .timeline-title strong{font-size:10px}
+ .mission-dock .timeline-items{padding:8px}.mission-dock .timeline-items > button{flex-basis:220px;min-height:134px;padding:10px}.mission-map-card{width:168px}
+ .biome-grove{transform:scale(.72)}.grove-b{transform:scale(.64)}
+}
+
+/* Shared registered roles: always visible, deliberately coarse, and distinct from reviewed stories. */
+.shared-walker-npc .npc-character { filter: drop-shadow(0 7px 7px rgba(83,139,153,.28)); }
+.npc .shared-walker-tag { border-color: rgba(126,182,202,.58); background: linear-gradient(145deg,rgba(22,42,40,.96),rgba(38,76,79,.96)); box-shadow: 0 14px 30px rgba(31,83,91,.2),0 0 0 4px rgba(126,182,202,.11); }
+.npc .shared-walker-tag::before { background: linear-gradient(90deg,transparent,var(--blue),var(--acid),transparent); }
+.npc .shared-walker-tag .npc-tag-label { color: #bfe5ef; }
+.npc .shared-walker-tag b { color: var(--ink); background: #bfe3ea; }
+.npc .shared-walker-tag i { color: #ecf5c7; background: rgba(217,240,93,.14); }
+.shared-walker-detail { box-shadow: 8px 8px 0 var(--blue); }
+.shared-walker-portrait { background: linear-gradient(145deg,#d5eced,#edf2ce); }
+.shared-walker-stage { display: flex; justify-content: space-between; gap: 18px; align-items: center; margin: 20px 0 0; padding: 16px 18px; border: 1px solid #c5d9d8; border-radius: 16px; background: linear-gradient(145deg,#e6f2ef,#f1f2dc); }
+.shared-walker-stage span { color: #65807c; font: 900 11px var(--font-mono); letter-spacing: .08em; }.shared-walker-stage strong { color: #265c5c; font-size: 18px; }
+.shared-walker-copy { margin: 18px 0; color: var(--muted); font-size: 14px; line-height: 1.75; }
+
+/* The real-life explainer lives high on the map so it can never cover zoom controls. */
+.reality-rules { top: 152px; bottom: auto; }
+.top-actions > .planner-open { color: #eef8ff; border-color: rgba(126,182,202,.62); background: rgba(126,182,202,.18); }
+.top-actions > .builder-open { color: var(--ink); border-color: rgba(217,240,93,.82); background: linear-gradient(135deg,#d9f05d,#f3e67b); font-weight: 900; box-shadow: 0 7px 20px rgba(217,240,93,.14); }
+.account-card > footer .account-build-link { color: #234e48; font-weight: 900; }
+
+/* Mobile-first repayment planner: the utility layer behind the world. */
+.mobile-planner-shade { position: fixed; z-index: 145; inset: 0; display: grid; place-items: center; padding: 18px; background: rgba(9,15,13,.72); backdrop-filter: blur(8px); }
+.mobile-planner-sheet { width: min(660px,100%); max-height: calc(100vh - 36px); overflow-y: auto; padding: 26px; border: 1px solid rgba(255,255,255,.22); border-radius: 28px; color: var(--ink); background: #f3f0e6; box-shadow: 0 28px 80px rgba(4,10,8,.35),8px 8px 0 var(--acid); }
+.mobile-planner-sheet > header { display: flex; justify-content: space-between; align-items: flex-start; gap: 18px; }.mobile-planner-sheet > header p { margin: 0 0 7px; color: #587a75; font: 900 11px var(--font-mono); letter-spacing: .08em; }.mobile-planner-sheet > header h2 { margin: 0; max-width: 500px; font-size: clamp(24px,4vw,36px); line-height: 1.08; letter-spacing: -.04em; }.mobile-planner-sheet > header button { width: 42px; height: 42px; flex: 0 0 auto; border: 1px solid #c6d1ca; border-radius: 50%; color: var(--ink); background: #fff; font-size: 25px; cursor: pointer; }
+.mobile-planner-summary { display: grid; grid-template-columns: 1fr 1fr; gap: 10px; margin: 21px 0 10px; }.mobile-planner-summary article { display: grid; gap: 7px; padding: 17px; border-radius: 18px; color: #fff; background: #213a36; }.mobile-planner-summary article:last-child { background: #3e6870; }.mobile-planner-summary article.negative { background: #a75946; }.mobile-planner-summary span { color: #cfe796; font: 800 9px var(--font-mono); letter-spacing: .06em; }.mobile-planner-summary strong { font: 900 22px var(--font-mono); }
+.mobile-plan-progress { padding: 16px; border: 1px solid #d5dbd1; border-radius: 18px; background: #fff; }.mobile-plan-progress > div { display: flex; justify-content: space-between; gap: 16px; }.mobile-plan-progress span { color: #607774; font: 900 10px var(--font-mono); }.mobile-plan-progress strong { color: #2a5e58; font-size: 17px; }.mobile-plan-progress > i { display: block; height: 9px; margin: 10px 0 8px; overflow: hidden; border-radius: 999px; background: #e7ebe3; }.mobile-plan-progress > i b { display: block; height: 100%; border-radius: inherit; background: linear-gradient(90deg,var(--coral),var(--acid)); }.mobile-plan-progress small { color: #73827d; font-size: 11px; }
+.mobile-plan-list { margin-top: 17px; }.mobile-plan-list .section-title { margin-bottom: 9px; }.mobile-plan-list > button { width: 100%; display: grid; grid-template-columns: 49px 1fr auto; gap: 11px; align-items: center; margin-top: 7px; padding: 11px; border: 1px solid #d3dcd5; border-radius: 15px; color: var(--ink); background: #fff; text-align: left; cursor: pointer; }.mobile-plan-list time { width: 49px; height: 49px; display: grid; place-items: center; align-content: center; border-radius: 13px; color: #fff; background: var(--coral); font-style: normal; }.mobile-plan-list time b { font-size: 18px; line-height: 1; }.mobile-plan-list time small { margin-top: 3px; font-size: 8px; text-transform: uppercase; }.mobile-plan-list > button > div { display: grid; gap: 4px; min-width: 0; }.mobile-plan-list > button > div strong { font-size: 14px; }.mobile-plan-list > button > div span { overflow: hidden; color: #667a76; font-size: 11px; text-overflow: ellipsis; white-space: nowrap; }.mobile-plan-list > button > em { color: #41746e; font-size: 10px; font-weight: 900; font-style: normal; }.mobile-plan-list > p { padding: 18px; border-radius: 15px; color: #61736f; background: #fff; font-size: 13px; line-height: 1.65; }
+.mobile-planner-actions { display: grid; grid-template-columns: 1.2fr 1fr 1fr; gap: 8px; margin-top: 16px; }.mobile-planner-actions button { min-height: 48px; border: 1px solid #c4d2c9; border-radius: 14px; color: #315e59; background: #fff; font-weight: 900; cursor: pointer; }.mobile-planner-actions button:first-child { color: var(--ink); border-color: var(--acid); background: var(--acid); }
+.mobile-planner-note { margin: 14px 0 0; padding: 12px 14px; border-left: 4px solid var(--blue); border-radius: 8px; color: #5d716d; background: #e6efea; font-size: 11px; line-height: 1.65; }
+@media (max-width: 760px) {
+ .mobile-planner-shade { align-items: end; padding: 0; }.mobile-planner-sheet { width: 100%; max-height: 92vh; padding: 22px 16px 26px; border-radius: 28px 28px 0 0; box-shadow: 0 -20px 60px rgba(4,10,8,.35); }.mobile-planner-summary { grid-template-columns: 1fr; }.mobile-planner-actions { grid-template-columns: 1fr; }.mobile-plan-list > button { grid-template-columns: 45px 1fr; }.mobile-plan-list > button > em { grid-column: 2; }.top-actions > .planner-open { max-width: none; }
+}
+
+/* Public builder gateway: contribution should feel like entering the world, not reading project paperwork. */
+.contribute-page { min-height: 100vh; overflow: hidden; color: var(--ink); background: #f2eee3; }
+.contribute-nav { min-height: 70px; display: flex; justify-content: space-between; align-items: center; gap: 18px; padding: 0 max(22px,calc((100vw - 1180px)/2)); border-bottom: 1px solid rgba(23,32,29,.15); background: rgba(242,238,227,.92); backdrop-filter: blur(16px); }
+.contribute-nav > a, .contribute-nav div a { color: #315f5b; font: 900 12px var(--font-mono); letter-spacing: .03em; }
+.contribute-nav div { display: flex; align-items: center; gap: 18px; }
+.contribute-hero { min-height: 680px; display: grid; grid-template-columns: minmax(0,1.08fr) minmax(410px,.92fr); gap: 60px; align-items: center; padding: 72px max(22px,calc((100vw - 1180px)/2)) 80px; background: radial-gradient(circle at 84% 22%,rgba(126,182,202,.27),transparent 27%),linear-gradient(150deg,#15332f 0 52%,#1f4842 100%); color: #fff; }
+.contribute-copy { max-width: 690px; }
+.contribute-copy > p, .contribute-tracks > header > p, .contribute-section-title p, .contribute-boundary > div p, .contribute-callout p { margin: 0 0 14px; color: var(--acid); font: 900 11px var(--font-mono); letter-spacing: .13em; }
+.contribute-copy h1 { margin: 0; font-size: clamp(48px,6.2vw,88px); line-height: .93; letter-spacing: -.075em; }
+.contribute-copy h1 em { display: block; color: var(--acid); font-style: normal; }
+.contribute-copy > span { display: block; max-width: 650px; margin-top: 30px; color: rgba(255,255,255,.76); font-size: clamp(16px,1.7vw,20px); line-height: 1.8; font-weight: 680; }
+.contribute-hero-actions { display: flex; flex-wrap: wrap; gap: 12px; margin-top: 30px; }
+.contribute-hero-actions a { min-height: 52px; display: inline-flex; align-items: center; justify-content: center; border: 1px solid var(--acid); border-radius: 999px; background: var(--acid); color: var(--ink); padding: 0 23px; font-size: 14px; font-weight: 950; }
+.contribute-hero-actions a.secondary { color: #fff; border-color: rgba(255,255,255,.38); background: transparent; }
+.contribute-copy > small { display: block; margin-top: 22px; color: rgba(255,255,255,.5); font: 700 11px/1.7 var(--font-mono); }
+.builder-world { position: relative; min-height: 490px; display: grid; place-items: center; isolation: isolate; }
+.builder-world::before { content: ""; position: absolute; inset: 14% 8%; z-index: -3; border-radius: 50%; background: radial-gradient(circle,rgba(217,240,93,.24),rgba(126,182,202,.08) 47%,transparent 68%); filter: blur(2px); }
+.builder-planet { width: 220px; aspect-ratio: 1; position: relative; display: grid; place-items: center; border: 1px solid rgba(255,255,255,.46); border-radius: 50%; background: radial-gradient(circle at 35% 28%,#f8f1c5 0 7%,#d9f05d 8% 26%,#6f9b85 27% 48%,#214a43 49% 100%); box-shadow: inset -25px -28px 44px rgba(8,27,24,.42),0 0 0 15px rgba(217,240,93,.06),0 30px 80px rgba(0,0,0,.3); }
+.builder-planet::after { content: ""; position: absolute; width: 128%; height: 34px; border: 2px solid rgba(126,182,202,.68); border-radius: 50%; transform: rotate(-14deg); box-shadow: 0 0 25px rgba(126,182,202,.32); }
+.builder-planet b { z-index: 1; color: #fff; font: 950 24px/.9 var(--font-mono); text-align: center; text-shadow: 0 3px 12px #173a34; }
+.builder-planet i { position: absolute; z-index: 2; right: 19px; top: 29px; color: #fff; font-style: normal; font-size: 26px; filter: drop-shadow(0 0 10px #fff); }
+.builder-orbit { position: absolute; z-index: -2; width: 410px; aspect-ratio: 1; border: 1px dashed rgba(255,255,255,.2); border-radius: 50%; }
+.builder-orbit.orbit-b { width: 330px; border-style: solid; border-color: rgba(217,240,93,.18); }
+.builder-piece { min-width: 120px; position: absolute; display: flex; align-items: center; gap: 9px; border: 1px solid rgba(255,255,255,.23); border-radius: 17px; background: rgba(12,34,31,.72); backdrop-filter: blur(10px); padding: 12px 14px; box-shadow: 0 14px 38px rgba(0,0,0,.2); }
+.builder-piece b { width: 39px; height: 39px; display: grid; place-items: center; border-radius: 12px; color: var(--ink); background: var(--acid); font: 950 14px var(--font-mono); }
+.builder-piece span { color: #fff; font: 900 10px var(--font-mono); letter-spacing: .08em; }
+.piece-language { left: 2%; top: 18%; transform: rotate(-4deg); }.piece-country { right: 0; top: 12%; transform: rotate(4deg); }.piece-test { left: 0; bottom: 14%; transform: rotate(3deg); }.piece-code { right: 2%; bottom: 17%; transform: rotate(-3deg); }
+.builder-world > p { position: absolute; bottom: -4px; margin: 0; color: rgba(255,255,255,.62); font-size: 13px; font-weight: 800; }
+.contribute-tracks { padding: 90px max(22px,calc((100vw - 1180px)/2)); }
+.contribute-tracks > header { max-width: 760px; }
+.contribute-tracks > header > p, .contribute-section-title p, .contribute-boundary > div p { color: #497770; }
+.contribute-tracks h2, .contribute-section-title h2, .contribute-boundary h2 { margin: 0; font-size: clamp(34px,4.2vw,58px); line-height: 1; letter-spacing: -.055em; }
+.contribute-tracks > header > span { display: block; margin-top: 17px; color: #677773; font-size: 17px; line-height: 1.7; }
+.contribute-track-grid { display: grid; grid-template-columns: repeat(4,1fr); gap: 12px; margin-top: 36px; }
+.contribute-track-grid article { min-height: 410px; display: flex; flex-direction: column; border: 1px solid rgba(23,32,29,.2); border-radius: 22px; background: #fff; padding: 22px; transition: transform .18s ease,box-shadow .18s ease; }
+.contribute-track-grid article:hover { transform: translateY(-5px); box-shadow: 0 20px 45px rgba(23,32,29,.1); }
+.contribute-track-grid article > div { display: flex; justify-content: space-between; align-items: center; gap: 8px; }.contribute-track-grid article > div span { color: #6d7f7b; font: 900 11px var(--font-mono); }.contribute-track-grid article > div b { border-radius: 999px; background: #edf1d6; padding: 6px 8px; color: #56706c; font: 900 9px var(--font-mono); }
+.contribute-track-grid article > i { width: 62px; height: 62px; display: grid; place-items: center; margin: 38px 0 22px; border-radius: 18px; color: var(--ink); background: var(--acid); box-shadow: 8px 8px 0 #d9e3bf; font: 950 19px var(--font-mono); font-style: normal; }
+.contribute-track-grid h3 { margin: 0; font-size: 23px; line-height: 1.13; letter-spacing: -.035em; }.contribute-track-grid p { color: #62736f; font-size: 14px; line-height: 1.75; }.contribute-track-grid article > a { margin-top: auto; border-top: 1px solid #dce1d9; padding-top: 18px; color: #285d57; font-size: 13px; font-weight: 950; }
+.contribute-growth { padding: 88px max(22px,calc((100vw - 1180px)/2)); color: #fff; background: #183a35; }
+.contribute-section-title { display: flex; align-items: flex-start; gap: 18px; max-width: 820px; }.contribute-section-title > span { width: 50px; height: 50px; flex: 0 0 auto; display: grid; place-items: center; border-radius: 50%; color: var(--ink); background: var(--acid); font: 950 11px var(--font-mono); }.contribute-section-title h2 { color: #fff; }
+.contribute-growth ol { display: grid; grid-template-columns: repeat(5,1fr); gap: 9px; margin: 42px 0 22px; padding: 0; list-style: none; }.contribute-growth li { min-height: 170px; display: flex; flex-direction: column; justify-content: space-between; border: 1px solid rgba(255,255,255,.16); border-radius: 18px; background: rgba(255,255,255,.05); padding: 18px; }.contribute-growth li b { color: var(--acid); font: 900 10px var(--font-mono); }.contribute-growth li span { color: rgba(255,255,255,.8); font-size: 14px; line-height: 1.55; font-weight: 800; }
+.contribute-growth aside { display: grid; grid-template-columns: .8fr 1.2fr; gap: 30px; border-radius: 20px; background: var(--acid); color: var(--ink); padding: 24px 28px; }.contribute-growth aside strong { font-size: 21px; line-height: 1.25; }.contribute-growth aside p { margin: 0; font-size: 13px; line-height: 1.7; font-weight: 760; }
+.contribute-boundary { display: grid; grid-template-columns: .82fr 1.18fr; gap: 55px; padding: 90px max(22px,calc((100vw - 1180px)/2)); }.contribute-boundary ul { display: grid; gap: 9px; margin: 0; padding: 0; list-style: none; }.contribute-boundary li { border-left: 5px solid var(--coral); border-radius: 0 15px 15px 0; background: #fff; padding: 16px 18px; color: #5c6c68; font-size: 14px; font-weight: 850; }.contribute-boundary > a { grid-column: 2; width: fit-content; color: #315f5b; font-weight: 950; }
+.contribute-callout { display: grid; grid-template-columns: auto 1fr auto; gap: 22px; align-items: center; margin: 0 max(22px,calc((100vw - 1180px)/2)) 90px; border-radius: 26px; background: #e86e4e; color: #fff; padding: 30px; box-shadow: 12px 12px 0 #173a35; }.contribute-callout > span { width: 64px; height: 64px; display: grid; place-items: center; border-radius: 50%; color: var(--ink); background: var(--acid); font-size: 26px; }.contribute-callout p { color: #fff7bf; }.contribute-callout h2 { margin: 0; font-size: clamp(25px,3vw,38px); line-height: 1.05; letter-spacing: -.04em; }.contribute-callout small { display: block; max-width: 720px; margin-top: 10px; color: rgba(255,255,255,.78); font-size: 12px; line-height: 1.6; }.contribute-callout > a { min-height: 48px; display: inline-flex; align-items: center; border-radius: 999px; background: #fff; color: var(--ink); padding: 0 19px; font-size: 13px; font-weight: 950; }
+.contribute-footer { display: grid; grid-template-columns: 1fr 1.4fr auto; gap: 25px; align-items: center; padding: 34px max(22px,calc((100vw - 1180px)/2)); color: rgba(255,255,255,.73); background: #0f2723; }.contribute-footer strong { color: var(--acid); font: 950 13px var(--font-mono); }.contribute-footer span { font-size: 13px; }.contribute-footer a { color: #fff; font-weight: 950; }
+
+@media (max-width: 980px) {
+ .contribute-hero { grid-template-columns: 1fr; gap: 30px; }.builder-world { min-height: 430px; }.contribute-track-grid { grid-template-columns: 1fr 1fr; }.contribute-growth ol { grid-template-columns: 1fr 1fr; }.contribute-growth li:last-child { grid-column: 1/-1; }.contribute-boundary { grid-template-columns: 1fr; }.contribute-boundary > a { grid-column: 1; }.contribute-callout { grid-template-columns: auto 1fr; }.contribute-callout > a { grid-column: 2; width: fit-content; }.contribute-footer { grid-template-columns: 1fr auto; }.contribute-footer span { grid-column: 1/-1; grid-row: 2; }
+}
+@media (max-width: 640px) {
+ .contribute-nav { min-height: 58px; padding-inline: 14px; }.contribute-nav div { gap: 11px; }.contribute-hero { min-height: auto; padding: 50px 16px 62px; }.contribute-copy h1 { font-size: clamp(43px,14vw,65px); }.contribute-copy > span { font-size: 16px; }.builder-world { min-height: 370px; transform: scale(.92); }.builder-planet { width: 180px; }.builder-orbit { width: 330px; }.builder-orbit.orbit-b { width: 260px; }.builder-piece { min-width: 96px; padding: 9px; }.builder-piece b { width: 32px; height: 32px; }.builder-piece span { font-size: 8px; }.contribute-tracks,.contribute-growth,.contribute-boundary { padding: 65px 16px; }.contribute-track-grid { grid-template-columns: 1fr; }.contribute-track-grid article { min-height: 340px; }.contribute-growth ol { grid-template-columns: 1fr; }.contribute-growth li:last-child { grid-column: auto; }.contribute-growth li { min-height: 130px; }.contribute-growth aside { grid-template-columns: 1fr; gap: 12px; padding: 21px; }.contribute-callout { grid-template-columns: 1fr; margin: 0 16px 65px; padding: 24px; }.contribute-callout > a { grid-column: 1; }.contribute-footer { grid-template-columns: 1fr; padding: 28px 16px; }.contribute-footer span { grid-column: 1; grid-row: auto; }.account-card > footer { flex-wrap: wrap; gap: 10px 16px; }
+}
diff --git a/app/layout.tsx b/app/layout.tsx
new file mode 100644
index 0000000..96cfe69
--- /dev/null
+++ b/app/layout.tsx
@@ -0,0 +1,52 @@
+import type { Metadata } from "next";
+import { headers } from "next/headers";
+import "./globals.css";
+
+export async function generateMetadata(): Promise {
+ const requestHeaders = await headers();
+ const host = requestHeaders.get("x-forwarded-host") ?? requestHeaders.get("host") ?? "localhost:3000";
+ const protocol = requestHeaders.get("x-forwarded-proto") ?? (host.startsWith("localhost") ? "http" : "https");
+ const socialImage = `${protocol}://${host}/og-beta.png`;
+
+ return {
+ metadataBase: new URL(`${protocol}://${host}`),
+ title: "上岸星球 Debt World — 让债务进度在真实世界里发生",
+ description: "一个可以行走的匿名债务世界。通过对话拆解多笔负债,让还款日、余额与小人进度跟随真实生活变化。",
+ applicationName: "上岸星球 Debt World",
+ keywords: ["债务管理", "还款进度", "匿名债务社区", "debt tracker", "debt community", "repayment progress"],
+ authors: [{ name: "Debt World" }],
+ creator: "Debt World",
+ category: "personal finance education",
+ robots: { index: true, follow: true, googleBot: { index: true, follow: true, "max-image-preview": "large", "max-snippet": -1 } },
+ openGraph: {
+ title: "上岸星球 Debt World",
+ description: "把压力说出来,让进度在真实世界里发生。",
+ type: "website",
+ images: [{ url: socialImage, width: 1731, height: 909, alt: "上岸星球 Debt World — 看见真实压力,也看见正在前进的人" }],
+ },
+ twitter: {
+ card: "summary_large_image",
+ title: "上岸星球 Debt World",
+ description: "把压力说出来,让进度在真实世界里发生。",
+ images: [socialImage],
+ },
+ icons: {
+ icon: "/favicon.svg",
+ },
+ alternates: {
+ canonical: "/",
+ languages: {
+ "zh-CN": "/",
+ en: "/en",
+ },
+ },
+ };
+}
+
+export default function RootLayout({ children }: Readonly<{ children: React.ReactNode }>) {
+ return (
+
+ {children}
+
+ );
+}
diff --git a/app/page.tsx b/app/page.tsx
new file mode 100644
index 0000000..dfd9b5e
--- /dev/null
+++ b/app/page.tsx
@@ -0,0 +1,5 @@
+import AccountGate from "./AccountGate";
+
+export default function Home() {
+ return ;
+}
diff --git a/app/robots.ts b/app/robots.ts
new file mode 100644
index 0000000..1269044
--- /dev/null
+++ b/app/robots.ts
@@ -0,0 +1,9 @@
+import type { MetadataRoute } from "next";
+
+export default function robots(): MetadataRoute.Robots {
+ return {
+ rules: { userAgent: "*", allow: ["/", "/en", "/about", "/en/about", "/contribute", "/en/contribute", "/safety", "/en/safety"], disallow: ["/admin", "/api/"] },
+ sitemap: "https://www.debtworld.org/sitemap.xml",
+ host: "https://www.debtworld.org",
+ };
+}
diff --git a/app/safety/page.tsx b/app/safety/page.tsx
new file mode 100644
index 0000000..8f36ff4
--- /dev/null
+++ b/app/safety/page.tsx
@@ -0,0 +1,10 @@
+import type { Metadata } from "next";
+import SafetyCenter from "../SafetyCenter";
+
+export const metadata: Metadata = {
+ title: "安全中心 — 上岸星球",
+ description: "上岸星球的隐私说明、社区规则、数据删除和财务法律边界。",
+ alternates: { canonical: "/safety", languages: { "zh-CN": "/safety", en: "/en/safety" } },
+};
+
+export default function SafetyPage() { return ; }
diff --git a/app/sitemap.ts b/app/sitemap.ts
new file mode 100644
index 0000000..8520b3a
--- /dev/null
+++ b/app/sitemap.ts
@@ -0,0 +1,16 @@
+import type { MetadataRoute } from "next";
+
+export default function sitemap(): MetadataRoute.Sitemap {
+ const base = "https://www.debtworld.org";
+ const now = new Date();
+ return [
+ { url: `${base}/`, lastModified: now, changeFrequency: "weekly", priority: 1, alternates: { languages: { "zh-CN": `${base}/`, en: `${base}/en` } } },
+ { url: `${base}/en`, lastModified: now, changeFrequency: "weekly", priority: 1, alternates: { languages: { "zh-CN": `${base}/`, en: `${base}/en` } } },
+ { url: `${base}/about`, lastModified: now, changeFrequency: "monthly", priority: .8, alternates: { languages: { "zh-CN": `${base}/about`, en: `${base}/en/about` } } },
+ { url: `${base}/en/about`, lastModified: now, changeFrequency: "monthly", priority: .8, alternates: { languages: { "zh-CN": `${base}/about`, en: `${base}/en/about` } } },
+ { url: `${base}/contribute`, lastModified: now, changeFrequency: "weekly", priority: .85, alternates: { languages: { "zh-CN": `${base}/contribute`, en: `${base}/en/contribute` } } },
+ { url: `${base}/en/contribute`, lastModified: now, changeFrequency: "weekly", priority: .85, alternates: { languages: { "zh-CN": `${base}/contribute`, en: `${base}/en/contribute` } } },
+ { url: `${base}/safety`, lastModified: now, changeFrequency: "monthly", priority: .5 },
+ { url: `${base}/en/safety`, lastModified: now, changeFrequency: "monthly", priority: .5 },
+ ];
+}
diff --git a/build/sites-vite-plugin.ts b/build/sites-vite-plugin.ts
new file mode 100644
index 0000000..26563fd
--- /dev/null
+++ b/build/sites-vite-plugin.ts
@@ -0,0 +1,45 @@
+import { access, cp, mkdir, rm } from "node:fs/promises";
+import { resolve } from "node:path";
+import type { Plugin } from "vite";
+
+async function exists(path: string): Promise {
+ try {
+ await access(path);
+ return true;
+ } catch (error) {
+ if ((error as NodeJS.ErrnoException).code === "ENOENT") {
+ return false;
+ }
+ throw error;
+ }
+}
+
+// Packages Sites metadata and migrations after Vite finishes compiling.
+export function sites(): Plugin {
+ let root = process.cwd();
+
+ return {
+ name: "sites",
+ apply: "build",
+ configResolved(config) {
+ root = config.root;
+ },
+ async closeBundle() {
+ const outputDirectory = resolve(root, "dist", ".openai");
+ const hostingConfig = resolve(root, ".openai", "hosting.json");
+ const drizzleSource = resolve(root, "drizzle");
+
+ await rm(outputDirectory, { recursive: true, force: true });
+ await mkdir(outputDirectory, { recursive: true });
+
+ if (await exists(hostingConfig)) {
+ await cp(hostingConfig, resolve(outputDirectory, "hosting.json"));
+ }
+ if (await exists(drizzleSource)) {
+ await cp(drizzleSource, resolve(outputDirectory, "drizzle"), {
+ recursive: true,
+ });
+ }
+ },
+ };
+}
diff --git a/db/index.ts b/db/index.ts
new file mode 100644
index 0000000..e58ea47
--- /dev/null
+++ b/db/index.ts
@@ -0,0 +1,19 @@
+import { env } from "cloudflare:workers";
+import { drizzle } from "drizzle-orm/d1";
+import * as schema from "./schema";
+
+export function getD1() {
+ if (!env.DB) {
+ throw new Error(
+ "Cloudflare D1 binding `DB` is unavailable. Set the `d1` field in .openai/hosting.json to `DB` or let your control plane inject the real binding values before using the database."
+ );
+ }
+
+ return env.DB;
+}
+
+// Retained for the opt-in example route. Product routes use getD1() and
+// prepared statements so ownership checks stay explicit at each query.
+export function getDb() {
+ return drizzle(getD1(), { schema });
+}
diff --git a/db/schema.ts b/db/schema.ts
new file mode 100644
index 0000000..0f4c238
--- /dev/null
+++ b/db/schema.ts
@@ -0,0 +1,514 @@
+import { sql } from "drizzle-orm";
+import { index, integer, real, sqliteTable, text, uniqueIndex } from "drizzle-orm/sqlite-core";
+
+export const vaults = sqliteTable("vaults", {
+ id: text("id").primaryKey(),
+ recoveryHash: text("recovery_hash").notNull().unique(),
+ alias: text("alias").notNull(),
+ region: text("region").notNull(),
+ pressure: text("pressure").notNull().default(""),
+ ageBand: text("age_band").notNull().default(""),
+ gender: text("gender").notNull().default(""),
+ mbti: text("mbti").notNull().default(""),
+ zodiac: text("zodiac").notNull().default(""),
+ selfDescription: text("self_description").notNull().default(""),
+ repaymentPlan: text("repayment_plan").notNull().default(""),
+ repaymentOutlook: text("repayment_outlook").notNull().default(""),
+ incomePlan: text("income_plan").notNull().default(""),
+ positionX: real("position_x").notNull().default(47),
+ positionY: real("position_y").notNull().default(63),
+ locale: text("locale").notNull().default("zh"),
+ countryCode: text("country_code").notNull().default(""),
+ countryName: text("country_name").notNull().default(""),
+ displayCurrency: text("display_currency").notNull().default("CNY"),
+ monthlyIncome: real("monthly_income").notNull().default(0),
+ monthlyExpenses: real("monthly_expenses").notNull().default(0),
+ discoveryConsent: integer("discovery_consent", { mode: "boolean" }).notNull().default(false),
+ createdAt: text("created_at").notNull().default(sql`CURRENT_TIMESTAMP`),
+ updatedAt: text("updated_at").notNull().default(sql`CURRENT_TIMESTAMP`),
+});
+
+export const accounts = sqliteTable(
+ "accounts",
+ {
+ id: text("id").primaryKey(),
+ userCode: text("user_code").notNull().unique(),
+ username: text("username").notNull(),
+ usernameNormalized: text("username_normalized").notNull().unique(),
+ passwordHash: text("password_hash").notNull(),
+ passwordSalt: text("password_salt").notNull(),
+ passwordIterations: integer("password_iterations").notNull(),
+ status: text("status").notNull().default("active"),
+ signupSource: text("signup_source").notNull().default("direct"),
+ createdAt: text("created_at").notNull().default(sql`CURRENT_TIMESTAMP`),
+ updatedAt: text("updated_at").notNull().default(sql`CURRENT_TIMESTAMP`),
+ lastLoginAt: text("last_login_at"),
+ lastSeenAt: text("last_seen_at"),
+ },
+ (table) => [index("accounts_created_idx").on(table.createdAt)],
+);
+
+export const accountSessions = sqliteTable(
+ "account_sessions",
+ {
+ id: text("id").primaryKey(),
+ accountId: text("account_id").notNull().references(() => accounts.id, { onDelete: "cascade" }),
+ tokenHash: text("token_hash").notNull().unique(),
+ expiresAt: text("expires_at").notNull(),
+ createdAt: text("created_at").notNull().default(sql`CURRENT_TIMESTAMP`),
+ lastSeenAt: text("last_seen_at").notNull().default(sql`CURRENT_TIMESTAMP`),
+ },
+ (table) => [
+ index("account_sessions_account_idx").on(table.accountId),
+ index("account_sessions_expires_idx").on(table.expiresAt),
+ ],
+);
+
+export const accountVaults = sqliteTable(
+ "account_vaults",
+ {
+ accountId: text("account_id").primaryKey().references(() => accounts.id, { onDelete: "cascade" }),
+ vaultId: text("vault_id").notNull().unique().references(() => vaults.id, { onDelete: "cascade" }),
+ linkedAt: text("linked_at").notNull().default(sql`CURRENT_TIMESTAMP`),
+ },
+ (table) => [index("account_vaults_vault_idx").on(table.vaultId)],
+);
+
+export const accountAuthLimits = sqliteTable(
+ "account_auth_limits",
+ {
+ limitKey: text("limit_key").primaryKey(),
+ action: text("action").notNull(),
+ windowKey: text("window_key").notNull(),
+ attempts: integer("attempts").notNull().default(0),
+ updatedAt: text("updated_at").notNull().default(sql`CURRENT_TIMESTAMP`),
+ },
+ (table) => [index("account_auth_limits_window_idx").on(table.windowKey)],
+);
+
+export const ownerAdmins = sqliteTable("owner_admins", {
+ id: text("id").primaryKey(),
+ emailDigest: text("email_digest").notNull().unique(),
+ accountId: text("account_id").unique().references(() => accounts.id, { onDelete: "set null" }),
+ role: text("role").notNull().default("owner"),
+ activatedAt: text("activated_at").notNull().default(sql`CURRENT_TIMESTAMP`),
+ lastSeenAt: text("last_seen_at").notNull().default(sql`CURRENT_TIMESTAMP`),
+});
+
+export const debts = sqliteTable(
+ "debts",
+ {
+ id: text("id").primaryKey(),
+ vaultId: text("vault_id")
+ .notNull()
+ .references(() => vaults.id, { onDelete: "cascade" }),
+ kind: text("kind").notNull(),
+ customLabel: text("custom_label"),
+ currency: text("currency").notNull(),
+ original: real("original").notNull(),
+ balance: real("balance").notNull(),
+ monthly: real("monthly").notNull(),
+ apr: real("apr"),
+ minimumPayment: real("minimum_payment"),
+ paymentStatus: text("payment_status").notNull().default("unknown"),
+ remainingMonths: integer("remaining_months"),
+ dueDay: integer("due_day").notNull(),
+ method: text("method").notNull(),
+ sharingMode: text("sharing_mode").notNull().default("private"),
+ lastPaidAt: text("last_paid_at"),
+ payments: integer("payments").notNull().default(0),
+ createdAt: text("created_at").notNull().default(sql`CURRENT_TIMESTAMP`),
+ updatedAt: text("updated_at").notNull().default(sql`CURRENT_TIMESTAMP`),
+ },
+ (table) => [index("debts_vault_id_idx").on(table.vaultId)],
+);
+
+export const paymentRecords = sqliteTable(
+ "payment_records",
+ {
+ id: text("id").primaryKey(),
+ vaultId: text("vault_id")
+ .notNull()
+ .references(() => vaults.id, { onDelete: "cascade" }),
+ debtId: text("debt_id")
+ .notNull()
+ .references(() => debts.id, { onDelete: "cascade" }),
+ scheduledDate: text("scheduled_date"),
+ confirmedAt: text("confirmed_at").notNull(),
+ eventDate: text("event_date"),
+ cashPayment: real("cash_payment").notNull(),
+ newBalance: real("new_balance").notNull(),
+ source: text("source").notNull().default("self_report"),
+ incomeType: text("income_type"),
+ createdAt: text("created_at").notNull().default(sql`CURRENT_TIMESTAMP`),
+ },
+ (table) => [
+ index("payments_vault_id_idx").on(table.vaultId),
+ index("payments_debt_id_idx").on(table.debtId),
+ ],
+);
+
+export const shoreValueLedger = sqliteTable(
+ "shore_value_ledger",
+ {
+ id: text("id").primaryKey(),
+ vaultId: text("vault_id").notNull().references(() => vaults.id, { onDelete: "cascade" }),
+ eventKey: text("event_key").notNull().unique(),
+ eventType: text("event_type").notNull(),
+ points: integer("points").notNull(),
+ referenceId: text("reference_id"),
+ createdAt: text("created_at").notNull().default(sql`CURRENT_TIMESTAMP`),
+ },
+ (table) => [
+ index("shore_value_vault_created_idx").on(table.vaultId, table.createdAt),
+ index("shore_value_event_type_idx").on(table.eventType),
+ ],
+);
+
+export const starlightWallets = sqliteTable("starlight_wallets", {
+ vaultId: text("vault_id").primaryKey().references(() => vaults.id, { onDelete: "cascade" }),
+ available: integer("available").notNull().default(0),
+ lifetimeEarned: integer("lifetime_earned").notNull().default(0),
+ lifetimeSent: integer("lifetime_sent").notNull().default(0),
+ lifetimeReceived: integer("lifetime_received").notNull().default(0),
+ updatedAt: text("updated_at").notNull().default(sql`CURRENT_TIMESTAMP`),
+});
+
+export const starlightGifts = sqliteTable(
+ "starlight_gifts",
+ {
+ id: text("id").primaryKey(),
+ senderVaultId: text("sender_vault_id").notNull().references(() => vaults.id, { onDelete: "cascade" }),
+ recipientVaultId: text("recipient_vault_id").notNull().references(() => vaults.id, { onDelete: "cascade" }),
+ storyId: text("story_id"),
+ points: integer("points").notNull(),
+ giftDate: text("gift_date").notNull(),
+ idempotencyKey: text("idempotency_key").notNull().unique(),
+ createdAt: text("created_at").notNull().default(sql`CURRENT_TIMESTAMP`),
+ },
+ (table) => [
+ index("starlight_sender_created_idx").on(table.senderVaultId, table.createdAt),
+ index("starlight_recipient_created_idx").on(table.recipientVaultId, table.createdAt),
+ ],
+);
+
+export const referralCodes = sqliteTable(
+ "referral_codes",
+ {
+ id: text("id").primaryKey(),
+ vaultId: text("vault_id").notNull().unique().references(() => vaults.id, { onDelete: "cascade" }),
+ code: text("code").notNull().unique(),
+ status: text("status").notNull().default("active"),
+ createdAt: text("created_at").notNull().default(sql`CURRENT_TIMESTAMP`),
+ },
+ (table) => [index("referral_codes_status_idx").on(table.status)],
+);
+
+export const referralRelationships = sqliteTable(
+ "referral_relationships",
+ {
+ id: text("id").primaryKey(),
+ inviterVaultId: text("inviter_vault_id").notNull().references(() => vaults.id, { onDelete: "cascade" }),
+ invitedVaultId: text("invited_vault_id").notNull().unique().references(() => vaults.id, { onDelete: "cascade" }),
+ codeId: text("code_id").notNull().references(() => referralCodes.id, { onDelete: "cascade" }),
+ status: text("status").notNull().default("pending"),
+ qualifiedAt: text("qualified_at"),
+ rewardedAt: text("rewarded_at"),
+ createdAt: text("created_at").notNull().default(sql`CURRENT_TIMESTAMP`),
+ },
+ (table) => [
+ index("referrals_inviter_status_idx").on(table.inviterVaultId, table.status),
+ index("referrals_created_idx").on(table.createdAt),
+ ],
+);
+
+export const siteDailyVisitors = sqliteTable(
+ "site_daily_visitors",
+ {
+ id: text("id").primaryKey(),
+ visitDate: text("visit_date").notNull(),
+ visitorDigest: text("visitor_digest").notNull(),
+ firstSource: text("first_source").notNull().default("direct"),
+ firstLocale: text("first_locale").notNull().default("zh"),
+ firstPath: text("first_path").notNull().default("/"),
+ pageViews: integer("page_views").notNull().default(1),
+ firstSeenAt: text("first_seen_at").notNull().default(sql`CURRENT_TIMESTAMP`),
+ lastSeenAt: text("last_seen_at").notNull().default(sql`CURRENT_TIMESTAMP`),
+ },
+ (table) => [
+ uniqueIndex("site_daily_visitors_date_digest_unique").on(table.visitDate, table.visitorDigest),
+ index("site_daily_visitors_date_idx").on(table.visitDate),
+ index("site_daily_visitors_source_date_idx").on(table.firstSource, table.visitDate),
+ ],
+);
+
+export const luckyIncomeClaims = sqliteTable(
+ "lucky_income_claims",
+ {
+ id: text("id").primaryKey(),
+ vaultId: text("vault_id").notNull().references(() => vaults.id, { onDelete: "cascade" }),
+ eventDate: text("event_date").notNull(),
+ createdAt: text("created_at").notNull().default(sql`CURRENT_TIMESTAMP`),
+ },
+ (table) => [
+ uniqueIndex("lucky_income_vault_day_unique").on(table.vaultId, table.eventDate),
+ ],
+);
+
+export const publicStories = sqliteTable(
+ "public_stories",
+ {
+ id: text("id").primaryKey(),
+ vaultId: text("vault_id").notNull().references(() => vaults.id, { onDelete: "cascade" }),
+ debtId: text("debt_id").notNull().references(() => debts.id, { onDelete: "cascade" }),
+ anonymousName: text("anonymous_name").notNull(),
+ countryCode: text("country_code").notNull().default(""),
+ debtKind: text("debt_kind").notNull(),
+ amountBand: text("amount_band").notNull(),
+ currency: text("currency").notNull(),
+ repaymentApproach: text("repayment_approach").notNull().default("other"),
+ storyText: text("story_text").notNull(),
+ status: text("status").notNull().default("pending"),
+ createdAt: text("created_at").notNull().default(sql`CURRENT_TIMESTAMP`),
+ updatedAt: text("updated_at").notNull().default(sql`CURRENT_TIMESTAMP`),
+ },
+ (table) => [
+ index("public_stories_status_idx").on(table.status),
+ index("public_stories_vault_idx").on(table.vaultId),
+ ],
+);
+
+export const storyEncouragements = sqliteTable(
+ "story_encouragements",
+ {
+ id: text("id").primaryKey(),
+ storyId: text("story_id").notNull().references(() => publicStories.id, { onDelete: "cascade" }),
+ vaultId: text("vault_id").notNull().references(() => vaults.id, { onDelete: "cascade" }),
+ createdAt: text("created_at").notNull().default(sql`CURRENT_TIMESTAMP`),
+ },
+ (table) => [
+ uniqueIndex("story_encouragement_unique").on(table.storyId, table.vaultId),
+ index("story_encouragement_story_idx").on(table.storyId),
+ ],
+);
+
+export const storyReports = sqliteTable(
+ "story_reports",
+ {
+ id: text("id").primaryKey(),
+ storyId: text("story_id").notNull().references(() => publicStories.id, { onDelete: "cascade" }),
+ reporterVaultId: text("reporter_vault_id").notNull().references(() => vaults.id, { onDelete: "cascade" }),
+ reason: text("reason").notNull(),
+ details: text("details").notNull().default(""),
+ status: text("status").notNull().default("open"),
+ createdAt: text("created_at").notNull().default(sql`CURRENT_TIMESTAMP`),
+ resolvedAt: text("resolved_at"),
+ },
+ (table) => [
+ uniqueIndex("story_report_unique").on(table.storyId, table.reporterVaultId),
+ index("story_reports_status_idx").on(table.status),
+ ],
+);
+
+export const communityRateLimits = sqliteTable(
+ "community_rate_limits",
+ {
+ id: text("id").primaryKey(),
+ vaultId: text("vault_id").notNull().references(() => vaults.id, { onDelete: "cascade" }),
+ action: text("action").notNull(),
+ windowKey: text("window_key").notNull(),
+ count: integer("count").notNull().default(0),
+ updatedAt: text("updated_at").notNull().default(sql`CURRENT_TIMESTAMP`),
+ },
+ (table) => [
+ uniqueIndex("community_rate_vault_action_window_unique").on(table.vaultId, table.action, table.windowKey),
+ index("community_rate_window_idx").on(table.windowKey),
+ ],
+);
+
+export const communityModerationActions = sqliteTable(
+ "community_moderation_actions",
+ {
+ id: text("id").primaryKey(),
+ storyId: text("story_id").notNull().references(() => publicStories.id, { onDelete: "cascade" }),
+ actorDigest: text("actor_digest").notNull(),
+ action: text("action").notNull(),
+ fromStatus: text("from_status").notNull(),
+ toStatus: text("to_status").notNull(),
+ note: text("note").notNull().default(""),
+ createdAt: text("created_at").notNull().default(sql`CURRENT_TIMESTAMP`),
+ },
+ (table) => [
+ index("community_moderation_story_idx").on(table.storyId),
+ index("community_moderation_created_idx").on(table.createdAt),
+ ],
+);
+
+export const policyAcceptances = sqliteTable(
+ "policy_acceptances",
+ {
+ id: text("id").primaryKey(),
+ vaultId: text("vault_id").notNull().references(() => vaults.id, { onDelete: "cascade" }),
+ policyKey: text("policy_key").notNull(),
+ policyVersion: text("policy_version").notNull(),
+ acceptedAt: text("accepted_at").notNull().default(sql`CURRENT_TIMESTAMP`),
+ },
+ (table) => [
+ uniqueIndex("policy_acceptance_vault_key_version_unique").on(table.vaultId, table.policyKey, table.policyVersion),
+ index("policy_acceptance_vault_idx").on(table.vaultId),
+ ],
+);
+
+export const aiDailyUsage = sqliteTable(
+ "ai_daily_usage",
+ {
+ id: text("id").primaryKey(),
+ vaultId: text("vault_id").notNull().references(() => vaults.id, { onDelete: "cascade" }),
+ usageDate: text("usage_date").notNull(),
+ requestCount: integer("request_count").notNull().default(0),
+ inputTokens: integer("input_tokens").notNull().default(0),
+ outputTokens: integer("output_tokens").notNull().default(0),
+ updatedAt: text("updated_at").notNull().default(sql`CURRENT_TIMESTAMP`),
+ },
+ (table) => [
+ uniqueIndex("ai_daily_usage_vault_date_unique").on(table.vaultId, table.usageDate),
+ index("ai_daily_usage_date_idx").on(table.usageDate),
+ ],
+);
+
+export const betaInviteCounters = sqliteTable("beta_invite_counters", {
+ inviteDigest: text("invite_digest").primaryKey(),
+ uses: integer("uses").notNull().default(0),
+ maxUses: integer("max_uses").notNull(),
+ updatedAt: text("updated_at").notNull().default(sql`CURRENT_TIMESTAMP`),
+});
+
+export const betaEnrollments = sqliteTable(
+ "beta_enrollments",
+ {
+ id: text("id").primaryKey(),
+ vaultId: text("vault_id").notNull().unique().references(() => vaults.id, { onDelete: "cascade" }),
+ inviteDigest: text("invite_digest").notNull(),
+ consentVersion: text("consent_version").notNull(),
+ createdAt: text("created_at").notNull().default(sql`CURRENT_TIMESTAMP`),
+ },
+ (table) => [index("beta_enrollments_created_idx").on(table.createdAt)],
+);
+
+export const betaFeedback = sqliteTable(
+ "beta_feedback",
+ {
+ id: text("id").primaryKey(),
+ vaultId: text("vault_id").notNull().references(() => vaults.id, { onDelete: "cascade" }),
+ category: text("category").notNull(),
+ rating: integer("rating").notNull(),
+ message: text("message").notNull(),
+ pagePath: text("page_path").notNull().default("/"),
+ status: text("status").notNull().default("open"),
+ createdAt: text("created_at").notNull().default(sql`CURRENT_TIMESTAMP`),
+ resolvedAt: text("resolved_at"),
+ },
+ (table) => [
+ index("beta_feedback_vault_idx").on(table.vaultId),
+ index("beta_feedback_status_idx").on(table.status),
+ ],
+);
+
+export const betaRuntimeSettings = sqliteTable("beta_runtime_settings", {
+ id: text("id").primaryKey(),
+ signupsEnabled: integer("signups_enabled", { mode: "boolean" }).notNull(),
+ updatedByDigest: text("updated_by_digest"),
+ updatedAt: text("updated_at").notNull().default(sql`CURRENT_TIMESTAMP`),
+});
+
+export const worldWeightProfiles = sqliteTable("world_weight_profiles", {
+ id: text("id").primaryKey(),
+ version: integer("version").notNull().unique(),
+ status: text("status").notNull().default("draft"),
+ frequencyWeight: real("frequency_weight").notNull(),
+ growthWeight: real("growth_weight").notNull(),
+ geographyWeight: real("geography_weight").notNull(),
+ recurrenceWeight: real("recurrence_weight").notNull(),
+ connectionWeight: real("connection_weight").notNull(),
+ qualityWeight: real("quality_weight").notNull(),
+ proposedBy: text("proposed_by").notNull().default("human"),
+ modelRef: text("model_ref"),
+ rationale: text("rationale").notNull().default(""),
+ createdAt: text("created_at").notNull().default(sql`CURRENT_TIMESTAMP`),
+ activatedAt: text("activated_at"),
+});
+
+export const worldCategoryCandidates = sqliteTable(
+ "world_category_candidates",
+ {
+ id: text("id").primaryKey(),
+ canonicalKey: text("canonical_key").notNull().unique(),
+ parentKind: text("parent_kind").notNull().default("other"),
+ nameZh: text("name_zh").notNull(),
+ nameEn: text("name_en").notNull(),
+ descriptionZh: text("description_zh").notNull().default(""),
+ descriptionEn: text("description_en").notNull().default(""),
+ status: text("status").notNull().default("candidate"),
+ stage: integer("stage").notNull().default(0),
+ confidence: real("confidence").notNull().default(0),
+ uniqueVaults: integer("unique_vaults").notNull().default(0),
+ regionCount: integer("region_count").notNull().default(0),
+ mentionCount: integer("mention_count").notNull().default(0),
+ emergenceScore: real("emergence_score").notNull().default(0),
+ weightProfileId: text("weight_profile_id").references(() => worldWeightProfiles.id),
+ mergedIntoId: text("merged_into_id"),
+ proposedAt: text("proposed_at").notNull().default(sql`CURRENT_TIMESTAMP`),
+ reviewedAt: text("reviewed_at"),
+ publishedAt: text("published_at"),
+ updatedAt: text("updated_at").notNull().default(sql`CURRENT_TIMESTAMP`),
+ },
+ (table) => [
+ index("world_candidates_status_idx").on(table.status),
+ index("world_candidates_score_idx").on(table.emergenceScore),
+ ],
+);
+
+export const worldSignalAssignments = sqliteTable(
+ "world_signal_assignments",
+ {
+ id: text("id").primaryKey(),
+ vaultId: text("vault_id")
+ .notNull()
+ .references(() => vaults.id, { onDelete: "cascade" }),
+ debtId: text("debt_id")
+ .notNull()
+ .unique()
+ .references(() => debts.id, { onDelete: "cascade" }),
+ candidateId: text("candidate_id")
+ .notNull()
+ .references(() => worldCategoryCandidates.id, { onDelete: "cascade" }),
+ confidence: real("confidence").notNull(),
+ assignmentSource: text("assignment_source").notNull().default("ai"),
+ taxonomyVersion: integer("taxonomy_version").notNull().default(1),
+ createdAt: text("created_at").notNull().default(sql`CURRENT_TIMESTAMP`),
+ updatedAt: text("updated_at").notNull().default(sql`CURRENT_TIMESTAMP`),
+ },
+ (table) => [
+ index("world_signals_vault_idx").on(table.vaultId),
+ index("world_signals_candidate_idx").on(table.candidateId),
+ ],
+);
+
+export const worldGrowthEvents = sqliteTable(
+ "world_growth_events",
+ {
+ id: text("id").primaryKey(),
+ candidateId: text("candidate_id")
+ .notNull()
+ .references(() => worldCategoryCandidates.id, { onDelete: "cascade" }),
+ eventType: text("event_type").notNull(),
+ fromStage: integer("from_stage"),
+ toStage: integer("to_stage"),
+ actorType: text("actor_type").notNull().default("system"),
+ weightProfileId: text("weight_profile_id").references(() => worldWeightProfiles.id),
+ evidenceJson: text("evidence_json").notNull().default("{}"),
+ reason: text("reason").notNull().default(""),
+ createdAt: text("created_at").notNull().default(sql`CURRENT_TIMESTAMP`),
+ },
+ (table) => [index("world_events_candidate_idx").on(table.candidateId)],
+);
diff --git a/drizzle.config.ts b/drizzle.config.ts
new file mode 100644
index 0000000..c2b2f34
--- /dev/null
+++ b/drizzle.config.ts
@@ -0,0 +1,7 @@
+import { defineConfig } from "drizzle-kit";
+
+export default defineConfig({
+ out: "./drizzle",
+ schema: "./db/schema.ts",
+ dialect: "sqlite",
+});
diff --git a/drizzle/0000_oval_jocasta.sql b/drizzle/0000_oval_jocasta.sql
new file mode 100644
index 0000000..e761cc4
--- /dev/null
+++ b/drizzle/0000_oval_jocasta.sql
@@ -0,0 +1,48 @@
+CREATE TABLE `debts` (
+ `id` text PRIMARY KEY NOT NULL,
+ `vault_id` text NOT NULL,
+ `kind` text NOT NULL,
+ `currency` text NOT NULL,
+ `original` real NOT NULL,
+ `balance` real NOT NULL,
+ `monthly` real NOT NULL,
+ `due_day` integer NOT NULL,
+ `method` text NOT NULL,
+ `last_paid_at` text,
+ `payments` integer DEFAULT 0 NOT NULL,
+ `created_at` text DEFAULT CURRENT_TIMESTAMP NOT NULL,
+ `updated_at` text DEFAULT CURRENT_TIMESTAMP NOT NULL,
+ FOREIGN KEY (`vault_id`) REFERENCES `vaults`(`id`) ON UPDATE no action ON DELETE cascade
+);
+--> statement-breakpoint
+CREATE INDEX `debts_vault_id_idx` ON `debts` (`vault_id`);--> statement-breakpoint
+CREATE TABLE `payment_records` (
+ `id` text PRIMARY KEY NOT NULL,
+ `vault_id` text NOT NULL,
+ `debt_id` text NOT NULL,
+ `scheduled_date` text,
+ `confirmed_at` text NOT NULL,
+ `cash_payment` real NOT NULL,
+ `new_balance` real NOT NULL,
+ `source` text DEFAULT 'self_report' NOT NULL,
+ `created_at` text DEFAULT CURRENT_TIMESTAMP NOT NULL,
+ FOREIGN KEY (`vault_id`) REFERENCES `vaults`(`id`) ON UPDATE no action ON DELETE cascade,
+ FOREIGN KEY (`debt_id`) REFERENCES `debts`(`id`) ON UPDATE no action ON DELETE cascade
+);
+--> statement-breakpoint
+CREATE INDEX `payments_vault_id_idx` ON `payment_records` (`vault_id`);--> statement-breakpoint
+CREATE INDEX `payments_debt_id_idx` ON `payment_records` (`debt_id`);--> statement-breakpoint
+CREATE TABLE `vaults` (
+ `id` text PRIMARY KEY NOT NULL,
+ `recovery_hash` text NOT NULL,
+ `alias` text NOT NULL,
+ `region` text NOT NULL,
+ `pressure` text DEFAULT '' NOT NULL,
+ `position_x` real DEFAULT 47 NOT NULL,
+ `position_y` real DEFAULT 63 NOT NULL,
+ `locale` text DEFAULT 'zh' NOT NULL,
+ `created_at` text DEFAULT CURRENT_TIMESTAMP NOT NULL,
+ `updated_at` text DEFAULT CURRENT_TIMESTAMP NOT NULL
+);
+--> statement-breakpoint
+CREATE UNIQUE INDEX `vaults_recovery_hash_unique` ON `vaults` (`recovery_hash`);
\ No newline at end of file
diff --git a/drizzle/0001_sad_wendell_vaughn.sql b/drizzle/0001_sad_wendell_vaughn.sql
new file mode 100644
index 0000000..28e4c60
--- /dev/null
+++ b/drizzle/0001_sad_wendell_vaughn.sql
@@ -0,0 +1,81 @@
+CREATE TABLE `world_category_candidates` (
+ `id` text PRIMARY KEY NOT NULL,
+ `canonical_key` text NOT NULL,
+ `parent_kind` text DEFAULT 'other' NOT NULL,
+ `name_zh` text NOT NULL,
+ `name_en` text NOT NULL,
+ `description_zh` text DEFAULT '' NOT NULL,
+ `description_en` text DEFAULT '' NOT NULL,
+ `status` text DEFAULT 'candidate' NOT NULL,
+ `stage` integer DEFAULT 0 NOT NULL,
+ `confidence` real DEFAULT 0 NOT NULL,
+ `unique_vaults` integer DEFAULT 0 NOT NULL,
+ `region_count` integer DEFAULT 0 NOT NULL,
+ `mention_count` integer DEFAULT 0 NOT NULL,
+ `emergence_score` real DEFAULT 0 NOT NULL,
+ `weight_profile_id` text,
+ `merged_into_id` text,
+ `proposed_at` text DEFAULT CURRENT_TIMESTAMP NOT NULL,
+ `reviewed_at` text,
+ `published_at` text,
+ `updated_at` text DEFAULT CURRENT_TIMESTAMP NOT NULL,
+ FOREIGN KEY (`weight_profile_id`) REFERENCES `world_weight_profiles`(`id`) ON UPDATE no action ON DELETE no action
+);
+--> statement-breakpoint
+CREATE UNIQUE INDEX `world_category_candidates_canonical_key_unique` ON `world_category_candidates` (`canonical_key`);--> statement-breakpoint
+CREATE INDEX `world_candidates_status_idx` ON `world_category_candidates` (`status`);--> statement-breakpoint
+CREATE INDEX `world_candidates_score_idx` ON `world_category_candidates` (`emergence_score`);--> statement-breakpoint
+CREATE TABLE `world_growth_events` (
+ `id` text PRIMARY KEY NOT NULL,
+ `candidate_id` text NOT NULL,
+ `event_type` text NOT NULL,
+ `from_stage` integer,
+ `to_stage` integer,
+ `actor_type` text DEFAULT 'system' NOT NULL,
+ `weight_profile_id` text,
+ `evidence_json` text DEFAULT '{}' NOT NULL,
+ `reason` text DEFAULT '' NOT NULL,
+ `created_at` text DEFAULT CURRENT_TIMESTAMP NOT NULL,
+ FOREIGN KEY (`candidate_id`) REFERENCES `world_category_candidates`(`id`) ON UPDATE no action ON DELETE cascade,
+ FOREIGN KEY (`weight_profile_id`) REFERENCES `world_weight_profiles`(`id`) ON UPDATE no action ON DELETE no action
+);
+--> statement-breakpoint
+CREATE INDEX `world_events_candidate_idx` ON `world_growth_events` (`candidate_id`);--> statement-breakpoint
+CREATE TABLE `world_signal_assignments` (
+ `id` text PRIMARY KEY NOT NULL,
+ `vault_id` text NOT NULL,
+ `debt_id` text NOT NULL,
+ `candidate_id` text NOT NULL,
+ `confidence` real NOT NULL,
+ `assignment_source` text DEFAULT 'ai' NOT NULL,
+ `taxonomy_version` integer DEFAULT 1 NOT NULL,
+ `created_at` text DEFAULT CURRENT_TIMESTAMP NOT NULL,
+ `updated_at` text DEFAULT CURRENT_TIMESTAMP NOT NULL,
+ FOREIGN KEY (`vault_id`) REFERENCES `vaults`(`id`) ON UPDATE no action ON DELETE cascade,
+ FOREIGN KEY (`debt_id`) REFERENCES `debts`(`id`) ON UPDATE no action ON DELETE cascade,
+ FOREIGN KEY (`candidate_id`) REFERENCES `world_category_candidates`(`id`) ON UPDATE no action ON DELETE cascade
+);
+--> statement-breakpoint
+CREATE UNIQUE INDEX `world_signal_assignments_debt_id_unique` ON `world_signal_assignments` (`debt_id`);--> statement-breakpoint
+CREATE INDEX `world_signals_vault_idx` ON `world_signal_assignments` (`vault_id`);--> statement-breakpoint
+CREATE INDEX `world_signals_candidate_idx` ON `world_signal_assignments` (`candidate_id`);--> statement-breakpoint
+CREATE TABLE `world_weight_profiles` (
+ `id` text PRIMARY KEY NOT NULL,
+ `version` integer NOT NULL,
+ `status` text DEFAULT 'draft' NOT NULL,
+ `frequency_weight` real NOT NULL,
+ `growth_weight` real NOT NULL,
+ `geography_weight` real NOT NULL,
+ `recurrence_weight` real NOT NULL,
+ `connection_weight` real NOT NULL,
+ `quality_weight` real NOT NULL,
+ `proposed_by` text DEFAULT 'human' NOT NULL,
+ `model_ref` text,
+ `rationale` text DEFAULT '' NOT NULL,
+ `created_at` text DEFAULT CURRENT_TIMESTAMP NOT NULL,
+ `activated_at` text
+);
+--> statement-breakpoint
+CREATE UNIQUE INDEX `world_weight_profiles_version_unique` ON `world_weight_profiles` (`version`);--> statement-breakpoint
+ALTER TABLE `debts` ADD `custom_label` text;--> statement-breakpoint
+ALTER TABLE `vaults` ADD `discovery_consent` integer DEFAULT false NOT NULL;
\ No newline at end of file
diff --git a/drizzle/0002_pink_next_avengers.sql b/drizzle/0002_pink_next_avengers.sql
new file mode 100644
index 0000000..6aab656
--- /dev/null
+++ b/drizzle/0002_pink_next_avengers.sql
@@ -0,0 +1,4 @@
+ALTER TABLE `vaults` ADD `country_code` text DEFAULT '' NOT NULL;--> statement-breakpoint
+ALTER TABLE `vaults` ADD `country_name` text DEFAULT '' NOT NULL;--> statement-breakpoint
+ALTER TABLE `vaults` ADD `display_currency` text DEFAULT 'CNY' NOT NULL;--> statement-breakpoint
+ALTER TABLE `vaults` ADD `monthly_income` real DEFAULT 0 NOT NULL;
\ No newline at end of file
diff --git a/drizzle/0003_tough_black_bird.sql b/drizzle/0003_tough_black_bird.sql
new file mode 100644
index 0000000..343f57e
--- /dev/null
+++ b/drizzle/0003_tough_black_bird.sql
@@ -0,0 +1 @@
+ALTER TABLE `vaults` ADD `monthly_expenses` real DEFAULT 0 NOT NULL;
\ No newline at end of file
diff --git a/drizzle/0004_skinny_xavin.sql b/drizzle/0004_skinny_xavin.sql
new file mode 100644
index 0000000..e90f9e2
--- /dev/null
+++ b/drizzle/0004_skinny_xavin.sql
@@ -0,0 +1 @@
+ALTER TABLE `debts` ADD `sharing_mode` text DEFAULT 'private' NOT NULL;
\ No newline at end of file
diff --git a/drizzle/0005_curious_ultragirl.sql b/drizzle/0005_curious_ultragirl.sql
new file mode 100644
index 0000000..e6a6e68
--- /dev/null
+++ b/drizzle/0005_curious_ultragirl.sql
@@ -0,0 +1,60 @@
+CREATE TABLE `lucky_income_claims` (
+ `id` text PRIMARY KEY NOT NULL,
+ `vault_id` text NOT NULL,
+ `debt_id` text NOT NULL,
+ `event_date` text NOT NULL,
+ `created_at` text DEFAULT CURRENT_TIMESTAMP NOT NULL,
+ FOREIGN KEY (`vault_id`) REFERENCES `vaults`(`id`) ON UPDATE no action ON DELETE cascade,
+ FOREIGN KEY (`debt_id`) REFERENCES `debts`(`id`) ON UPDATE no action ON DELETE cascade
+);
+--> statement-breakpoint
+CREATE UNIQUE INDEX `lucky_income_vault_day_unique` ON `lucky_income_claims` (`vault_id`,`event_date`);--> statement-breakpoint
+CREATE INDEX `lucky_income_debt_idx` ON `lucky_income_claims` (`debt_id`);--> statement-breakpoint
+CREATE TABLE `public_stories` (
+ `id` text PRIMARY KEY NOT NULL,
+ `vault_id` text NOT NULL,
+ `debt_id` text NOT NULL,
+ `anonymous_name` text NOT NULL,
+ `country_code` text DEFAULT '' NOT NULL,
+ `debt_kind` text NOT NULL,
+ `amount_band` text NOT NULL,
+ `currency` text NOT NULL,
+ `repayment_approach` text DEFAULT 'other' NOT NULL,
+ `story_text` text NOT NULL,
+ `status` text DEFAULT 'pending' NOT NULL,
+ `created_at` text DEFAULT CURRENT_TIMESTAMP NOT NULL,
+ `updated_at` text DEFAULT CURRENT_TIMESTAMP NOT NULL,
+ FOREIGN KEY (`vault_id`) REFERENCES `vaults`(`id`) ON UPDATE no action ON DELETE cascade,
+ FOREIGN KEY (`debt_id`) REFERENCES `debts`(`id`) ON UPDATE no action ON DELETE cascade
+);
+--> statement-breakpoint
+CREATE INDEX `public_stories_status_idx` ON `public_stories` (`status`);--> statement-breakpoint
+CREATE INDEX `public_stories_vault_idx` ON `public_stories` (`vault_id`);--> statement-breakpoint
+CREATE TABLE `story_encouragements` (
+ `id` text PRIMARY KEY NOT NULL,
+ `story_id` text NOT NULL,
+ `vault_id` text NOT NULL,
+ `created_at` text DEFAULT CURRENT_TIMESTAMP NOT NULL,
+ FOREIGN KEY (`story_id`) REFERENCES `public_stories`(`id`) ON UPDATE no action ON DELETE cascade,
+ FOREIGN KEY (`vault_id`) REFERENCES `vaults`(`id`) ON UPDATE no action ON DELETE cascade
+);
+--> statement-breakpoint
+CREATE UNIQUE INDEX `story_encouragement_unique` ON `story_encouragements` (`story_id`,`vault_id`);--> statement-breakpoint
+CREATE INDEX `story_encouragement_story_idx` ON `story_encouragements` (`story_id`);--> statement-breakpoint
+CREATE TABLE `story_reports` (
+ `id` text PRIMARY KEY NOT NULL,
+ `story_id` text NOT NULL,
+ `reporter_vault_id` text NOT NULL,
+ `reason` text NOT NULL,
+ `details` text DEFAULT '' NOT NULL,
+ `status` text DEFAULT 'open' NOT NULL,
+ `created_at` text DEFAULT CURRENT_TIMESTAMP NOT NULL,
+ `resolved_at` text,
+ FOREIGN KEY (`story_id`) REFERENCES `public_stories`(`id`) ON UPDATE no action ON DELETE cascade,
+ FOREIGN KEY (`reporter_vault_id`) REFERENCES `vaults`(`id`) ON UPDATE no action ON DELETE cascade
+);
+--> statement-breakpoint
+CREATE UNIQUE INDEX `story_report_unique` ON `story_reports` (`story_id`,`reporter_vault_id`);--> statement-breakpoint
+CREATE INDEX `story_reports_status_idx` ON `story_reports` (`status`);--> statement-breakpoint
+ALTER TABLE `payment_records` ADD `event_date` text;--> statement-breakpoint
+ALTER TABLE `payment_records` ADD `income_type` text;
\ No newline at end of file
diff --git a/drizzle/0006_supreme_james_howlett.sql b/drizzle/0006_supreme_james_howlett.sql
new file mode 100644
index 0000000..14a377f
--- /dev/null
+++ b/drizzle/0006_supreme_james_howlett.sql
@@ -0,0 +1,14 @@
+PRAGMA foreign_keys=OFF;--> statement-breakpoint
+CREATE TABLE `__new_lucky_income_claims` (
+ `id` text PRIMARY KEY NOT NULL,
+ `vault_id` text NOT NULL,
+ `event_date` text NOT NULL,
+ `created_at` text DEFAULT CURRENT_TIMESTAMP NOT NULL,
+ FOREIGN KEY (`vault_id`) REFERENCES `vaults`(`id`) ON UPDATE no action ON DELETE cascade
+);
+--> statement-breakpoint
+INSERT INTO `__new_lucky_income_claims`("id", "vault_id", "event_date", "created_at") SELECT "id", "vault_id", "event_date", "created_at" FROM `lucky_income_claims`;--> statement-breakpoint
+DROP TABLE `lucky_income_claims`;--> statement-breakpoint
+ALTER TABLE `__new_lucky_income_claims` RENAME TO `lucky_income_claims`;--> statement-breakpoint
+PRAGMA foreign_keys=ON;--> statement-breakpoint
+CREATE UNIQUE INDEX `lucky_income_vault_day_unique` ON `lucky_income_claims` (`vault_id`,`event_date`);
\ No newline at end of file
diff --git a/drizzle/0007_faulty_nova.sql b/drizzle/0007_faulty_nova.sql
new file mode 100644
index 0000000..74bbd73
--- /dev/null
+++ b/drizzle/0007_faulty_nova.sql
@@ -0,0 +1,26 @@
+CREATE TABLE `community_moderation_actions` (
+ `id` text PRIMARY KEY NOT NULL,
+ `story_id` text NOT NULL,
+ `actor_digest` text NOT NULL,
+ `action` text NOT NULL,
+ `from_status` text NOT NULL,
+ `to_status` text NOT NULL,
+ `note` text DEFAULT '' NOT NULL,
+ `created_at` text DEFAULT CURRENT_TIMESTAMP NOT NULL,
+ FOREIGN KEY (`story_id`) REFERENCES `public_stories`(`id`) ON UPDATE no action ON DELETE cascade
+);
+--> statement-breakpoint
+CREATE INDEX `community_moderation_story_idx` ON `community_moderation_actions` (`story_id`);--> statement-breakpoint
+CREATE INDEX `community_moderation_created_idx` ON `community_moderation_actions` (`created_at`);--> statement-breakpoint
+CREATE TABLE `community_rate_limits` (
+ `id` text PRIMARY KEY NOT NULL,
+ `vault_id` text NOT NULL,
+ `action` text NOT NULL,
+ `window_key` text NOT NULL,
+ `count` integer DEFAULT 0 NOT NULL,
+ `updated_at` text DEFAULT CURRENT_TIMESTAMP NOT NULL,
+ FOREIGN KEY (`vault_id`) REFERENCES `vaults`(`id`) ON UPDATE no action ON DELETE cascade
+);
+--> statement-breakpoint
+CREATE UNIQUE INDEX `community_rate_vault_action_window_unique` ON `community_rate_limits` (`vault_id`,`action`,`window_key`);--> statement-breakpoint
+CREATE INDEX `community_rate_window_idx` ON `community_rate_limits` (`window_key`);
\ No newline at end of file
diff --git a/drizzle/0008_shiny_squirrel_girl.sql b/drizzle/0008_shiny_squirrel_girl.sql
new file mode 100644
index 0000000..20ab9de
--- /dev/null
+++ b/drizzle/0008_shiny_squirrel_girl.sql
@@ -0,0 +1,11 @@
+CREATE TABLE `policy_acceptances` (
+ `id` text PRIMARY KEY NOT NULL,
+ `vault_id` text NOT NULL,
+ `policy_key` text NOT NULL,
+ `policy_version` text NOT NULL,
+ `accepted_at` text DEFAULT CURRENT_TIMESTAMP NOT NULL,
+ FOREIGN KEY (`vault_id`) REFERENCES `vaults`(`id`) ON UPDATE no action ON DELETE cascade
+);
+--> statement-breakpoint
+CREATE UNIQUE INDEX `policy_acceptance_vault_key_version_unique` ON `policy_acceptances` (`vault_id`,`policy_key`,`policy_version`);--> statement-breakpoint
+CREATE INDEX `policy_acceptance_vault_idx` ON `policy_acceptances` (`vault_id`);
\ No newline at end of file
diff --git a/drizzle/0009_numerous_marvex.sql b/drizzle/0009_numerous_marvex.sql
new file mode 100644
index 0000000..2a449a1
--- /dev/null
+++ b/drizzle/0009_numerous_marvex.sql
@@ -0,0 +1,13 @@
+CREATE TABLE `ai_daily_usage` (
+ `id` text PRIMARY KEY NOT NULL,
+ `vault_id` text NOT NULL,
+ `usage_date` text NOT NULL,
+ `request_count` integer DEFAULT 0 NOT NULL,
+ `input_tokens` integer DEFAULT 0 NOT NULL,
+ `output_tokens` integer DEFAULT 0 NOT NULL,
+ `updated_at` text DEFAULT CURRENT_TIMESTAMP NOT NULL,
+ FOREIGN KEY (`vault_id`) REFERENCES `vaults`(`id`) ON UPDATE no action ON DELETE cascade
+);
+--> statement-breakpoint
+CREATE UNIQUE INDEX `ai_daily_usage_vault_date_unique` ON `ai_daily_usage` (`vault_id`,`usage_date`);--> statement-breakpoint
+CREATE INDEX `ai_daily_usage_date_idx` ON `ai_daily_usage` (`usage_date`);
\ No newline at end of file
diff --git a/drizzle/0010_opposite_solo.sql b/drizzle/0010_opposite_solo.sql
new file mode 100644
index 0000000..e04e7f1
--- /dev/null
+++ b/drizzle/0010_opposite_solo.sql
@@ -0,0 +1,4 @@
+ALTER TABLE `debts` ADD `apr` real;--> statement-breakpoint
+ALTER TABLE `debts` ADD `minimum_payment` real;--> statement-breakpoint
+ALTER TABLE `debts` ADD `payment_status` text DEFAULT 'unknown' NOT NULL;--> statement-breakpoint
+ALTER TABLE `debts` ADD `remaining_months` integer;
\ No newline at end of file
diff --git a/drizzle/0011_bent_black_knight.sql b/drizzle/0011_bent_black_knight.sql
new file mode 100644
index 0000000..a1effc4
--- /dev/null
+++ b/drizzle/0011_bent_black_knight.sql
@@ -0,0 +1,39 @@
+CREATE TABLE `beta_enrollments` (
+ `id` text PRIMARY KEY NOT NULL,
+ `vault_id` text NOT NULL,
+ `invite_digest` text NOT NULL,
+ `consent_version` text NOT NULL,
+ `created_at` text DEFAULT CURRENT_TIMESTAMP NOT NULL,
+ FOREIGN KEY (`vault_id`) REFERENCES `vaults`(`id`) ON UPDATE no action ON DELETE cascade
+);
+--> statement-breakpoint
+CREATE UNIQUE INDEX `beta_enrollments_vault_id_unique` ON `beta_enrollments` (`vault_id`);--> statement-breakpoint
+CREATE INDEX `beta_enrollments_created_idx` ON `beta_enrollments` (`created_at`);--> statement-breakpoint
+CREATE TABLE `beta_feedback` (
+ `id` text PRIMARY KEY NOT NULL,
+ `vault_id` text NOT NULL,
+ `category` text NOT NULL,
+ `rating` integer NOT NULL,
+ `message` text NOT NULL,
+ `page_path` text DEFAULT '/' NOT NULL,
+ `status` text DEFAULT 'open' NOT NULL,
+ `created_at` text DEFAULT CURRENT_TIMESTAMP NOT NULL,
+ `resolved_at` text,
+ FOREIGN KEY (`vault_id`) REFERENCES `vaults`(`id`) ON UPDATE no action ON DELETE cascade
+);
+--> statement-breakpoint
+CREATE INDEX `beta_feedback_vault_idx` ON `beta_feedback` (`vault_id`);--> statement-breakpoint
+CREATE INDEX `beta_feedback_status_idx` ON `beta_feedback` (`status`);--> statement-breakpoint
+CREATE TABLE `beta_invite_counters` (
+ `invite_digest` text PRIMARY KEY NOT NULL,
+ `uses` integer DEFAULT 0 NOT NULL,
+ `max_uses` integer NOT NULL,
+ `updated_at` text DEFAULT CURRENT_TIMESTAMP NOT NULL
+);
+--> statement-breakpoint
+CREATE TABLE `beta_runtime_settings` (
+ `id` text PRIMARY KEY NOT NULL,
+ `signups_enabled` integer NOT NULL,
+ `updated_by_digest` text,
+ `updated_at` text DEFAULT CURRENT_TIMESTAMP NOT NULL
+);
diff --git a/drizzle/0012_overrated_alex_power.sql b/drizzle/0012_overrated_alex_power.sql
new file mode 100644
index 0000000..315c37e
--- /dev/null
+++ b/drizzle/0012_overrated_alex_power.sql
@@ -0,0 +1,59 @@
+CREATE TABLE `account_auth_limits` (
+ `limit_key` text PRIMARY KEY NOT NULL,
+ `action` text NOT NULL,
+ `window_key` text NOT NULL,
+ `attempts` integer DEFAULT 0 NOT NULL,
+ `updated_at` text DEFAULT CURRENT_TIMESTAMP NOT NULL
+);
+--> statement-breakpoint
+CREATE INDEX `account_auth_limits_window_idx` ON `account_auth_limits` (`window_key`);--> statement-breakpoint
+CREATE TABLE `account_sessions` (
+ `id` text PRIMARY KEY NOT NULL,
+ `account_id` text NOT NULL,
+ `token_hash` text NOT NULL,
+ `expires_at` text NOT NULL,
+ `created_at` text DEFAULT CURRENT_TIMESTAMP NOT NULL,
+ `last_seen_at` text DEFAULT CURRENT_TIMESTAMP NOT NULL,
+ FOREIGN KEY (`account_id`) REFERENCES `accounts`(`id`) ON UPDATE no action ON DELETE cascade
+);
+--> statement-breakpoint
+CREATE UNIQUE INDEX `account_sessions_token_hash_unique` ON `account_sessions` (`token_hash`);--> statement-breakpoint
+CREATE INDEX `account_sessions_account_idx` ON `account_sessions` (`account_id`);--> statement-breakpoint
+CREATE INDEX `account_sessions_expires_idx` ON `account_sessions` (`expires_at`);--> statement-breakpoint
+CREATE TABLE `account_vaults` (
+ `account_id` text PRIMARY KEY NOT NULL,
+ `vault_id` text NOT NULL,
+ `linked_at` text DEFAULT CURRENT_TIMESTAMP NOT NULL,
+ FOREIGN KEY (`account_id`) REFERENCES `accounts`(`id`) ON UPDATE no action ON DELETE cascade,
+ FOREIGN KEY (`vault_id`) REFERENCES `vaults`(`id`) ON UPDATE no action ON DELETE cascade
+);
+--> statement-breakpoint
+CREATE UNIQUE INDEX `account_vaults_vault_id_unique` ON `account_vaults` (`vault_id`);--> statement-breakpoint
+CREATE INDEX `account_vaults_vault_idx` ON `account_vaults` (`vault_id`);--> statement-breakpoint
+CREATE TABLE `accounts` (
+ `id` text PRIMARY KEY NOT NULL,
+ `user_code` text NOT NULL,
+ `username` text NOT NULL,
+ `username_normalized` text NOT NULL,
+ `password_hash` text NOT NULL,
+ `password_salt` text NOT NULL,
+ `password_iterations` integer NOT NULL,
+ `status` text DEFAULT 'active' NOT NULL,
+ `created_at` text DEFAULT CURRENT_TIMESTAMP NOT NULL,
+ `updated_at` text DEFAULT CURRENT_TIMESTAMP NOT NULL,
+ `last_login_at` text,
+ `last_seen_at` text
+);
+--> statement-breakpoint
+CREATE UNIQUE INDEX `accounts_user_code_unique` ON `accounts` (`user_code`);--> statement-breakpoint
+CREATE UNIQUE INDEX `accounts_username_normalized_unique` ON `accounts` (`username_normalized`);--> statement-breakpoint
+CREATE INDEX `accounts_created_idx` ON `accounts` (`created_at`);--> statement-breakpoint
+CREATE TABLE `owner_admins` (
+ `id` text PRIMARY KEY NOT NULL,
+ `email_digest` text NOT NULL,
+ `role` text DEFAULT 'owner' NOT NULL,
+ `activated_at` text DEFAULT CURRENT_TIMESTAMP NOT NULL,
+ `last_seen_at` text DEFAULT CURRENT_TIMESTAMP NOT NULL
+);
+--> statement-breakpoint
+CREATE UNIQUE INDEX `owner_admins_email_digest_unique` ON `owner_admins` (`email_digest`);
\ No newline at end of file
diff --git a/drizzle/0013_faithful_silverclaw.sql b/drizzle/0013_faithful_silverclaw.sql
new file mode 100644
index 0000000..3b8e963
--- /dev/null
+++ b/drizzle/0013_faithful_silverclaw.sql
@@ -0,0 +1,8 @@
+ALTER TABLE `vaults` ADD `age_band` text DEFAULT '' NOT NULL;--> statement-breakpoint
+ALTER TABLE `vaults` ADD `gender` text DEFAULT '' NOT NULL;--> statement-breakpoint
+ALTER TABLE `vaults` ADD `mbti` text DEFAULT '' NOT NULL;--> statement-breakpoint
+ALTER TABLE `vaults` ADD `zodiac` text DEFAULT '' NOT NULL;--> statement-breakpoint
+ALTER TABLE `vaults` ADD `self_description` text DEFAULT '' NOT NULL;--> statement-breakpoint
+ALTER TABLE `vaults` ADD `repayment_plan` text DEFAULT '' NOT NULL;--> statement-breakpoint
+ALTER TABLE `vaults` ADD `repayment_outlook` text DEFAULT '' NOT NULL;--> statement-breakpoint
+ALTER TABLE `vaults` ADD `income_plan` text DEFAULT '' NOT NULL;
\ No newline at end of file
diff --git a/drizzle/0014_sad_pestilence.sql b/drizzle/0014_sad_pestilence.sql
new file mode 100644
index 0000000..899de2c
--- /dev/null
+++ b/drizzle/0014_sad_pestilence.sql
@@ -0,0 +1,68 @@
+CREATE TABLE `referral_codes` (
+ `id` text PRIMARY KEY NOT NULL,
+ `vault_id` text NOT NULL,
+ `code` text NOT NULL,
+ `status` text DEFAULT 'active' NOT NULL,
+ `created_at` text DEFAULT CURRENT_TIMESTAMP NOT NULL,
+ FOREIGN KEY (`vault_id`) REFERENCES `vaults`(`id`) ON UPDATE no action ON DELETE cascade
+);
+--> statement-breakpoint
+CREATE UNIQUE INDEX `referral_codes_vault_id_unique` ON `referral_codes` (`vault_id`);--> statement-breakpoint
+CREATE UNIQUE INDEX `referral_codes_code_unique` ON `referral_codes` (`code`);--> statement-breakpoint
+CREATE INDEX `referral_codes_status_idx` ON `referral_codes` (`status`);--> statement-breakpoint
+CREATE TABLE `referral_relationships` (
+ `id` text PRIMARY KEY NOT NULL,
+ `inviter_vault_id` text NOT NULL,
+ `invited_vault_id` text NOT NULL,
+ `code_id` text NOT NULL,
+ `status` text DEFAULT 'pending' NOT NULL,
+ `qualified_at` text,
+ `rewarded_at` text,
+ `created_at` text DEFAULT CURRENT_TIMESTAMP NOT NULL,
+ FOREIGN KEY (`inviter_vault_id`) REFERENCES `vaults`(`id`) ON UPDATE no action ON DELETE cascade,
+ FOREIGN KEY (`invited_vault_id`) REFERENCES `vaults`(`id`) ON UPDATE no action ON DELETE cascade,
+ FOREIGN KEY (`code_id`) REFERENCES `referral_codes`(`id`) ON UPDATE no action ON DELETE cascade
+);
+--> statement-breakpoint
+CREATE UNIQUE INDEX `referral_relationships_invited_vault_id_unique` ON `referral_relationships` (`invited_vault_id`);--> statement-breakpoint
+CREATE INDEX `referrals_inviter_status_idx` ON `referral_relationships` (`inviter_vault_id`,`status`);--> statement-breakpoint
+CREATE INDEX `referrals_created_idx` ON `referral_relationships` (`created_at`);--> statement-breakpoint
+CREATE TABLE `shore_value_ledger` (
+ `id` text PRIMARY KEY NOT NULL,
+ `vault_id` text NOT NULL,
+ `event_key` text NOT NULL,
+ `event_type` text NOT NULL,
+ `points` integer NOT NULL,
+ `reference_id` text,
+ `created_at` text DEFAULT CURRENT_TIMESTAMP NOT NULL,
+ FOREIGN KEY (`vault_id`) REFERENCES `vaults`(`id`) ON UPDATE no action ON DELETE cascade
+);
+--> statement-breakpoint
+CREATE UNIQUE INDEX `shore_value_ledger_event_key_unique` ON `shore_value_ledger` (`event_key`);--> statement-breakpoint
+CREATE INDEX `shore_value_vault_created_idx` ON `shore_value_ledger` (`vault_id`,`created_at`);--> statement-breakpoint
+CREATE INDEX `shore_value_event_type_idx` ON `shore_value_ledger` (`event_type`);--> statement-breakpoint
+CREATE TABLE `starlight_gifts` (
+ `id` text PRIMARY KEY NOT NULL,
+ `sender_vault_id` text NOT NULL,
+ `recipient_vault_id` text NOT NULL,
+ `story_id` text,
+ `points` integer NOT NULL,
+ `gift_date` text NOT NULL,
+ `idempotency_key` text NOT NULL,
+ `created_at` text DEFAULT CURRENT_TIMESTAMP NOT NULL,
+ FOREIGN KEY (`sender_vault_id`) REFERENCES `vaults`(`id`) ON UPDATE no action ON DELETE cascade,
+ FOREIGN KEY (`recipient_vault_id`) REFERENCES `vaults`(`id`) ON UPDATE no action ON DELETE cascade
+);
+--> statement-breakpoint
+CREATE UNIQUE INDEX `starlight_gifts_idempotency_key_unique` ON `starlight_gifts` (`idempotency_key`);--> statement-breakpoint
+CREATE INDEX `starlight_sender_created_idx` ON `starlight_gifts` (`sender_vault_id`,`created_at`);--> statement-breakpoint
+CREATE INDEX `starlight_recipient_created_idx` ON `starlight_gifts` (`recipient_vault_id`,`created_at`);--> statement-breakpoint
+CREATE TABLE `starlight_wallets` (
+ `vault_id` text PRIMARY KEY NOT NULL,
+ `available` integer DEFAULT 0 NOT NULL,
+ `lifetime_earned` integer DEFAULT 0 NOT NULL,
+ `lifetime_sent` integer DEFAULT 0 NOT NULL,
+ `lifetime_received` integer DEFAULT 0 NOT NULL,
+ `updated_at` text DEFAULT CURRENT_TIMESTAMP NOT NULL,
+ FOREIGN KEY (`vault_id`) REFERENCES `vaults`(`id`) ON UPDATE no action ON DELETE cascade
+);
diff --git a/drizzle/0015_steep_praxagora.sql b/drizzle/0015_steep_praxagora.sql
new file mode 100644
index 0000000..5517458
--- /dev/null
+++ b/drizzle/0015_steep_praxagora.sql
@@ -0,0 +1 @@
+ALTER TABLE `accounts` ADD `signup_source` text DEFAULT 'direct' NOT NULL;
\ No newline at end of file
diff --git a/drizzle/0016_icy_magdalene.sql b/drizzle/0016_icy_magdalene.sql
new file mode 100644
index 0000000..7ca3831
--- /dev/null
+++ b/drizzle/0016_icy_magdalene.sql
@@ -0,0 +1,2 @@
+ALTER TABLE `owner_admins` ADD `account_id` text REFERENCES accounts(id) ON DELETE SET NULL;--> statement-breakpoint
+CREATE UNIQUE INDEX `owner_admins_account_id_unique` ON `owner_admins` (`account_id`);
diff --git a/drizzle/0017_last_hellcat.sql b/drizzle/0017_last_hellcat.sql
new file mode 100644
index 0000000..24ebac4
--- /dev/null
+++ b/drizzle/0017_last_hellcat.sql
@@ -0,0 +1,15 @@
+CREATE TABLE `site_daily_visitors` (
+ `id` text PRIMARY KEY NOT NULL,
+ `visit_date` text NOT NULL,
+ `visitor_digest` text NOT NULL,
+ `first_source` text DEFAULT 'direct' NOT NULL,
+ `first_locale` text DEFAULT 'zh' NOT NULL,
+ `first_path` text DEFAULT '/' NOT NULL,
+ `page_views` integer DEFAULT 1 NOT NULL,
+ `first_seen_at` text DEFAULT CURRENT_TIMESTAMP NOT NULL,
+ `last_seen_at` text DEFAULT CURRENT_TIMESTAMP NOT NULL
+);
+--> statement-breakpoint
+CREATE UNIQUE INDEX `site_daily_visitors_date_digest_unique` ON `site_daily_visitors` (`visit_date`,`visitor_digest`);--> statement-breakpoint
+CREATE INDEX `site_daily_visitors_date_idx` ON `site_daily_visitors` (`visit_date`);--> statement-breakpoint
+CREATE INDEX `site_daily_visitors_source_date_idx` ON `site_daily_visitors` (`first_source`,`visit_date`);
\ No newline at end of file
diff --git a/drizzle/meta/0000_snapshot.json b/drizzle/meta/0000_snapshot.json
new file mode 100644
index 0000000..7145d3d
--- /dev/null
+++ b/drizzle/meta/0000_snapshot.json
@@ -0,0 +1,355 @@
+{
+ "version": "6",
+ "dialect": "sqlite",
+ "id": "8668452d-e473-4df2-be53-eb12d35aec8f",
+ "prevId": "00000000-0000-0000-0000-000000000000",
+ "tables": {
+ "debts": {
+ "name": "debts",
+ "columns": {
+ "id": {
+ "name": "id",
+ "type": "text",
+ "primaryKey": true,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "vault_id": {
+ "name": "vault_id",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "kind": {
+ "name": "kind",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "currency": {
+ "name": "currency",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "original": {
+ "name": "original",
+ "type": "real",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "balance": {
+ "name": "balance",
+ "type": "real",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "monthly": {
+ "name": "monthly",
+ "type": "real",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "due_day": {
+ "name": "due_day",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "method": {
+ "name": "method",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "last_paid_at": {
+ "name": "last_paid_at",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": false,
+ "autoincrement": false
+ },
+ "payments": {
+ "name": "payments",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": 0
+ },
+ "created_at": {
+ "name": "created_at",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": "CURRENT_TIMESTAMP"
+ },
+ "updated_at": {
+ "name": "updated_at",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": "CURRENT_TIMESTAMP"
+ }
+ },
+ "indexes": {
+ "debts_vault_id_idx": {
+ "name": "debts_vault_id_idx",
+ "columns": [
+ "vault_id"
+ ],
+ "isUnique": false
+ }
+ },
+ "foreignKeys": {
+ "debts_vault_id_vaults_id_fk": {
+ "name": "debts_vault_id_vaults_id_fk",
+ "tableFrom": "debts",
+ "tableTo": "vaults",
+ "columnsFrom": [
+ "vault_id"
+ ],
+ "columnsTo": [
+ "id"
+ ],
+ "onDelete": "cascade",
+ "onUpdate": "no action"
+ }
+ },
+ "compositePrimaryKeys": {},
+ "uniqueConstraints": {},
+ "checkConstraints": {}
+ },
+ "payment_records": {
+ "name": "payment_records",
+ "columns": {
+ "id": {
+ "name": "id",
+ "type": "text",
+ "primaryKey": true,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "vault_id": {
+ "name": "vault_id",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "debt_id": {
+ "name": "debt_id",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "scheduled_date": {
+ "name": "scheduled_date",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": false,
+ "autoincrement": false
+ },
+ "confirmed_at": {
+ "name": "confirmed_at",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "cash_payment": {
+ "name": "cash_payment",
+ "type": "real",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "new_balance": {
+ "name": "new_balance",
+ "type": "real",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "source": {
+ "name": "source",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": "'self_report'"
+ },
+ "created_at": {
+ "name": "created_at",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": "CURRENT_TIMESTAMP"
+ }
+ },
+ "indexes": {
+ "payments_vault_id_idx": {
+ "name": "payments_vault_id_idx",
+ "columns": [
+ "vault_id"
+ ],
+ "isUnique": false
+ },
+ "payments_debt_id_idx": {
+ "name": "payments_debt_id_idx",
+ "columns": [
+ "debt_id"
+ ],
+ "isUnique": false
+ }
+ },
+ "foreignKeys": {
+ "payment_records_vault_id_vaults_id_fk": {
+ "name": "payment_records_vault_id_vaults_id_fk",
+ "tableFrom": "payment_records",
+ "tableTo": "vaults",
+ "columnsFrom": [
+ "vault_id"
+ ],
+ "columnsTo": [
+ "id"
+ ],
+ "onDelete": "cascade",
+ "onUpdate": "no action"
+ },
+ "payment_records_debt_id_debts_id_fk": {
+ "name": "payment_records_debt_id_debts_id_fk",
+ "tableFrom": "payment_records",
+ "tableTo": "debts",
+ "columnsFrom": [
+ "debt_id"
+ ],
+ "columnsTo": [
+ "id"
+ ],
+ "onDelete": "cascade",
+ "onUpdate": "no action"
+ }
+ },
+ "compositePrimaryKeys": {},
+ "uniqueConstraints": {},
+ "checkConstraints": {}
+ },
+ "vaults": {
+ "name": "vaults",
+ "columns": {
+ "id": {
+ "name": "id",
+ "type": "text",
+ "primaryKey": true,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "recovery_hash": {
+ "name": "recovery_hash",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "alias": {
+ "name": "alias",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "region": {
+ "name": "region",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "pressure": {
+ "name": "pressure",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": "''"
+ },
+ "position_x": {
+ "name": "position_x",
+ "type": "real",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": 47
+ },
+ "position_y": {
+ "name": "position_y",
+ "type": "real",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": 63
+ },
+ "locale": {
+ "name": "locale",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": "'zh'"
+ },
+ "created_at": {
+ "name": "created_at",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": "CURRENT_TIMESTAMP"
+ },
+ "updated_at": {
+ "name": "updated_at",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": "CURRENT_TIMESTAMP"
+ }
+ },
+ "indexes": {
+ "vaults_recovery_hash_unique": {
+ "name": "vaults_recovery_hash_unique",
+ "columns": [
+ "recovery_hash"
+ ],
+ "isUnique": true
+ }
+ },
+ "foreignKeys": {},
+ "compositePrimaryKeys": {},
+ "uniqueConstraints": {},
+ "checkConstraints": {}
+ }
+ },
+ "views": {},
+ "enums": {},
+ "_meta": {
+ "schemas": {},
+ "tables": {},
+ "columns": {}
+ },
+ "internal": {
+ "indexes": {}
+ }
+}
\ No newline at end of file
diff --git a/drizzle/meta/0001_snapshot.json b/drizzle/meta/0001_snapshot.json
new file mode 100644
index 0000000..2d27a98
--- /dev/null
+++ b/drizzle/meta/0001_snapshot.json
@@ -0,0 +1,946 @@
+{
+ "version": "6",
+ "dialect": "sqlite",
+ "id": "f007ca06-ef6a-4b2c-a7dc-54a3d660615f",
+ "prevId": "8668452d-e473-4df2-be53-eb12d35aec8f",
+ "tables": {
+ "debts": {
+ "name": "debts",
+ "columns": {
+ "id": {
+ "name": "id",
+ "type": "text",
+ "primaryKey": true,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "vault_id": {
+ "name": "vault_id",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "kind": {
+ "name": "kind",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "custom_label": {
+ "name": "custom_label",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": false,
+ "autoincrement": false
+ },
+ "currency": {
+ "name": "currency",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "original": {
+ "name": "original",
+ "type": "real",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "balance": {
+ "name": "balance",
+ "type": "real",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "monthly": {
+ "name": "monthly",
+ "type": "real",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "due_day": {
+ "name": "due_day",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "method": {
+ "name": "method",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "last_paid_at": {
+ "name": "last_paid_at",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": false,
+ "autoincrement": false
+ },
+ "payments": {
+ "name": "payments",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": 0
+ },
+ "created_at": {
+ "name": "created_at",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": "CURRENT_TIMESTAMP"
+ },
+ "updated_at": {
+ "name": "updated_at",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": "CURRENT_TIMESTAMP"
+ }
+ },
+ "indexes": {
+ "debts_vault_id_idx": {
+ "name": "debts_vault_id_idx",
+ "columns": [
+ "vault_id"
+ ],
+ "isUnique": false
+ }
+ },
+ "foreignKeys": {
+ "debts_vault_id_vaults_id_fk": {
+ "name": "debts_vault_id_vaults_id_fk",
+ "tableFrom": "debts",
+ "tableTo": "vaults",
+ "columnsFrom": [
+ "vault_id"
+ ],
+ "columnsTo": [
+ "id"
+ ],
+ "onDelete": "cascade",
+ "onUpdate": "no action"
+ }
+ },
+ "compositePrimaryKeys": {},
+ "uniqueConstraints": {},
+ "checkConstraints": {}
+ },
+ "payment_records": {
+ "name": "payment_records",
+ "columns": {
+ "id": {
+ "name": "id",
+ "type": "text",
+ "primaryKey": true,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "vault_id": {
+ "name": "vault_id",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "debt_id": {
+ "name": "debt_id",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "scheduled_date": {
+ "name": "scheduled_date",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": false,
+ "autoincrement": false
+ },
+ "confirmed_at": {
+ "name": "confirmed_at",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "cash_payment": {
+ "name": "cash_payment",
+ "type": "real",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "new_balance": {
+ "name": "new_balance",
+ "type": "real",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "source": {
+ "name": "source",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": "'self_report'"
+ },
+ "created_at": {
+ "name": "created_at",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": "CURRENT_TIMESTAMP"
+ }
+ },
+ "indexes": {
+ "payments_vault_id_idx": {
+ "name": "payments_vault_id_idx",
+ "columns": [
+ "vault_id"
+ ],
+ "isUnique": false
+ },
+ "payments_debt_id_idx": {
+ "name": "payments_debt_id_idx",
+ "columns": [
+ "debt_id"
+ ],
+ "isUnique": false
+ }
+ },
+ "foreignKeys": {
+ "payment_records_vault_id_vaults_id_fk": {
+ "name": "payment_records_vault_id_vaults_id_fk",
+ "tableFrom": "payment_records",
+ "tableTo": "vaults",
+ "columnsFrom": [
+ "vault_id"
+ ],
+ "columnsTo": [
+ "id"
+ ],
+ "onDelete": "cascade",
+ "onUpdate": "no action"
+ },
+ "payment_records_debt_id_debts_id_fk": {
+ "name": "payment_records_debt_id_debts_id_fk",
+ "tableFrom": "payment_records",
+ "tableTo": "debts",
+ "columnsFrom": [
+ "debt_id"
+ ],
+ "columnsTo": [
+ "id"
+ ],
+ "onDelete": "cascade",
+ "onUpdate": "no action"
+ }
+ },
+ "compositePrimaryKeys": {},
+ "uniqueConstraints": {},
+ "checkConstraints": {}
+ },
+ "vaults": {
+ "name": "vaults",
+ "columns": {
+ "id": {
+ "name": "id",
+ "type": "text",
+ "primaryKey": true,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "recovery_hash": {
+ "name": "recovery_hash",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "alias": {
+ "name": "alias",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "region": {
+ "name": "region",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "pressure": {
+ "name": "pressure",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": "''"
+ },
+ "position_x": {
+ "name": "position_x",
+ "type": "real",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": 47
+ },
+ "position_y": {
+ "name": "position_y",
+ "type": "real",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": 63
+ },
+ "locale": {
+ "name": "locale",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": "'zh'"
+ },
+ "discovery_consent": {
+ "name": "discovery_consent",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": false
+ },
+ "created_at": {
+ "name": "created_at",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": "CURRENT_TIMESTAMP"
+ },
+ "updated_at": {
+ "name": "updated_at",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": "CURRENT_TIMESTAMP"
+ }
+ },
+ "indexes": {
+ "vaults_recovery_hash_unique": {
+ "name": "vaults_recovery_hash_unique",
+ "columns": [
+ "recovery_hash"
+ ],
+ "isUnique": true
+ }
+ },
+ "foreignKeys": {},
+ "compositePrimaryKeys": {},
+ "uniqueConstraints": {},
+ "checkConstraints": {}
+ },
+ "world_category_candidates": {
+ "name": "world_category_candidates",
+ "columns": {
+ "id": {
+ "name": "id",
+ "type": "text",
+ "primaryKey": true,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "canonical_key": {
+ "name": "canonical_key",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "parent_kind": {
+ "name": "parent_kind",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": "'other'"
+ },
+ "name_zh": {
+ "name": "name_zh",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "name_en": {
+ "name": "name_en",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "description_zh": {
+ "name": "description_zh",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": "''"
+ },
+ "description_en": {
+ "name": "description_en",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": "''"
+ },
+ "status": {
+ "name": "status",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": "'candidate'"
+ },
+ "stage": {
+ "name": "stage",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": 0
+ },
+ "confidence": {
+ "name": "confidence",
+ "type": "real",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": 0
+ },
+ "unique_vaults": {
+ "name": "unique_vaults",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": 0
+ },
+ "region_count": {
+ "name": "region_count",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": 0
+ },
+ "mention_count": {
+ "name": "mention_count",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": 0
+ },
+ "emergence_score": {
+ "name": "emergence_score",
+ "type": "real",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": 0
+ },
+ "weight_profile_id": {
+ "name": "weight_profile_id",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": false,
+ "autoincrement": false
+ },
+ "merged_into_id": {
+ "name": "merged_into_id",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": false,
+ "autoincrement": false
+ },
+ "proposed_at": {
+ "name": "proposed_at",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": "CURRENT_TIMESTAMP"
+ },
+ "reviewed_at": {
+ "name": "reviewed_at",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": false,
+ "autoincrement": false
+ },
+ "published_at": {
+ "name": "published_at",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": false,
+ "autoincrement": false
+ },
+ "updated_at": {
+ "name": "updated_at",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": "CURRENT_TIMESTAMP"
+ }
+ },
+ "indexes": {
+ "world_category_candidates_canonical_key_unique": {
+ "name": "world_category_candidates_canonical_key_unique",
+ "columns": [
+ "canonical_key"
+ ],
+ "isUnique": true
+ },
+ "world_candidates_status_idx": {
+ "name": "world_candidates_status_idx",
+ "columns": [
+ "status"
+ ],
+ "isUnique": false
+ },
+ "world_candidates_score_idx": {
+ "name": "world_candidates_score_idx",
+ "columns": [
+ "emergence_score"
+ ],
+ "isUnique": false
+ }
+ },
+ "foreignKeys": {
+ "world_category_candidates_weight_profile_id_world_weight_profiles_id_fk": {
+ "name": "world_category_candidates_weight_profile_id_world_weight_profiles_id_fk",
+ "tableFrom": "world_category_candidates",
+ "tableTo": "world_weight_profiles",
+ "columnsFrom": [
+ "weight_profile_id"
+ ],
+ "columnsTo": [
+ "id"
+ ],
+ "onDelete": "no action",
+ "onUpdate": "no action"
+ }
+ },
+ "compositePrimaryKeys": {},
+ "uniqueConstraints": {},
+ "checkConstraints": {}
+ },
+ "world_growth_events": {
+ "name": "world_growth_events",
+ "columns": {
+ "id": {
+ "name": "id",
+ "type": "text",
+ "primaryKey": true,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "candidate_id": {
+ "name": "candidate_id",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "event_type": {
+ "name": "event_type",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "from_stage": {
+ "name": "from_stage",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": false,
+ "autoincrement": false
+ },
+ "to_stage": {
+ "name": "to_stage",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": false,
+ "autoincrement": false
+ },
+ "actor_type": {
+ "name": "actor_type",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": "'system'"
+ },
+ "weight_profile_id": {
+ "name": "weight_profile_id",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": false,
+ "autoincrement": false
+ },
+ "evidence_json": {
+ "name": "evidence_json",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": "'{}'"
+ },
+ "reason": {
+ "name": "reason",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": "''"
+ },
+ "created_at": {
+ "name": "created_at",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": "CURRENT_TIMESTAMP"
+ }
+ },
+ "indexes": {
+ "world_events_candidate_idx": {
+ "name": "world_events_candidate_idx",
+ "columns": [
+ "candidate_id"
+ ],
+ "isUnique": false
+ }
+ },
+ "foreignKeys": {
+ "world_growth_events_candidate_id_world_category_candidates_id_fk": {
+ "name": "world_growth_events_candidate_id_world_category_candidates_id_fk",
+ "tableFrom": "world_growth_events",
+ "tableTo": "world_category_candidates",
+ "columnsFrom": [
+ "candidate_id"
+ ],
+ "columnsTo": [
+ "id"
+ ],
+ "onDelete": "cascade",
+ "onUpdate": "no action"
+ },
+ "world_growth_events_weight_profile_id_world_weight_profiles_id_fk": {
+ "name": "world_growth_events_weight_profile_id_world_weight_profiles_id_fk",
+ "tableFrom": "world_growth_events",
+ "tableTo": "world_weight_profiles",
+ "columnsFrom": [
+ "weight_profile_id"
+ ],
+ "columnsTo": [
+ "id"
+ ],
+ "onDelete": "no action",
+ "onUpdate": "no action"
+ }
+ },
+ "compositePrimaryKeys": {},
+ "uniqueConstraints": {},
+ "checkConstraints": {}
+ },
+ "world_signal_assignments": {
+ "name": "world_signal_assignments",
+ "columns": {
+ "id": {
+ "name": "id",
+ "type": "text",
+ "primaryKey": true,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "vault_id": {
+ "name": "vault_id",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "debt_id": {
+ "name": "debt_id",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "candidate_id": {
+ "name": "candidate_id",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "confidence": {
+ "name": "confidence",
+ "type": "real",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "assignment_source": {
+ "name": "assignment_source",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": "'ai'"
+ },
+ "taxonomy_version": {
+ "name": "taxonomy_version",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": 1
+ },
+ "created_at": {
+ "name": "created_at",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": "CURRENT_TIMESTAMP"
+ },
+ "updated_at": {
+ "name": "updated_at",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": "CURRENT_TIMESTAMP"
+ }
+ },
+ "indexes": {
+ "world_signal_assignments_debt_id_unique": {
+ "name": "world_signal_assignments_debt_id_unique",
+ "columns": [
+ "debt_id"
+ ],
+ "isUnique": true
+ },
+ "world_signals_vault_idx": {
+ "name": "world_signals_vault_idx",
+ "columns": [
+ "vault_id"
+ ],
+ "isUnique": false
+ },
+ "world_signals_candidate_idx": {
+ "name": "world_signals_candidate_idx",
+ "columns": [
+ "candidate_id"
+ ],
+ "isUnique": false
+ }
+ },
+ "foreignKeys": {
+ "world_signal_assignments_vault_id_vaults_id_fk": {
+ "name": "world_signal_assignments_vault_id_vaults_id_fk",
+ "tableFrom": "world_signal_assignments",
+ "tableTo": "vaults",
+ "columnsFrom": [
+ "vault_id"
+ ],
+ "columnsTo": [
+ "id"
+ ],
+ "onDelete": "cascade",
+ "onUpdate": "no action"
+ },
+ "world_signal_assignments_debt_id_debts_id_fk": {
+ "name": "world_signal_assignments_debt_id_debts_id_fk",
+ "tableFrom": "world_signal_assignments",
+ "tableTo": "debts",
+ "columnsFrom": [
+ "debt_id"
+ ],
+ "columnsTo": [
+ "id"
+ ],
+ "onDelete": "cascade",
+ "onUpdate": "no action"
+ },
+ "world_signal_assignments_candidate_id_world_category_candidates_id_fk": {
+ "name": "world_signal_assignments_candidate_id_world_category_candidates_id_fk",
+ "tableFrom": "world_signal_assignments",
+ "tableTo": "world_category_candidates",
+ "columnsFrom": [
+ "candidate_id"
+ ],
+ "columnsTo": [
+ "id"
+ ],
+ "onDelete": "cascade",
+ "onUpdate": "no action"
+ }
+ },
+ "compositePrimaryKeys": {},
+ "uniqueConstraints": {},
+ "checkConstraints": {}
+ },
+ "world_weight_profiles": {
+ "name": "world_weight_profiles",
+ "columns": {
+ "id": {
+ "name": "id",
+ "type": "text",
+ "primaryKey": true,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "version": {
+ "name": "version",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "status": {
+ "name": "status",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": "'draft'"
+ },
+ "frequency_weight": {
+ "name": "frequency_weight",
+ "type": "real",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "growth_weight": {
+ "name": "growth_weight",
+ "type": "real",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "geography_weight": {
+ "name": "geography_weight",
+ "type": "real",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "recurrence_weight": {
+ "name": "recurrence_weight",
+ "type": "real",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "connection_weight": {
+ "name": "connection_weight",
+ "type": "real",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "quality_weight": {
+ "name": "quality_weight",
+ "type": "real",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "proposed_by": {
+ "name": "proposed_by",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": "'human'"
+ },
+ "model_ref": {
+ "name": "model_ref",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": false,
+ "autoincrement": false
+ },
+ "rationale": {
+ "name": "rationale",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": "''"
+ },
+ "created_at": {
+ "name": "created_at",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": "CURRENT_TIMESTAMP"
+ },
+ "activated_at": {
+ "name": "activated_at",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": false,
+ "autoincrement": false
+ }
+ },
+ "indexes": {
+ "world_weight_profiles_version_unique": {
+ "name": "world_weight_profiles_version_unique",
+ "columns": [
+ "version"
+ ],
+ "isUnique": true
+ }
+ },
+ "foreignKeys": {},
+ "compositePrimaryKeys": {},
+ "uniqueConstraints": {},
+ "checkConstraints": {}
+ }
+ },
+ "views": {},
+ "enums": {},
+ "_meta": {
+ "schemas": {},
+ "tables": {},
+ "columns": {}
+ },
+ "internal": {
+ "indexes": {}
+ }
+}
\ No newline at end of file
diff --git a/drizzle/meta/0002_snapshot.json b/drizzle/meta/0002_snapshot.json
new file mode 100644
index 0000000..84e1d94
--- /dev/null
+++ b/drizzle/meta/0002_snapshot.json
@@ -0,0 +1,978 @@
+{
+ "version": "6",
+ "dialect": "sqlite",
+ "id": "00b74bfb-5770-4d51-bb75-9527e61e1657",
+ "prevId": "f007ca06-ef6a-4b2c-a7dc-54a3d660615f",
+ "tables": {
+ "debts": {
+ "name": "debts",
+ "columns": {
+ "id": {
+ "name": "id",
+ "type": "text",
+ "primaryKey": true,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "vault_id": {
+ "name": "vault_id",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "kind": {
+ "name": "kind",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "custom_label": {
+ "name": "custom_label",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": false,
+ "autoincrement": false
+ },
+ "currency": {
+ "name": "currency",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "original": {
+ "name": "original",
+ "type": "real",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "balance": {
+ "name": "balance",
+ "type": "real",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "monthly": {
+ "name": "monthly",
+ "type": "real",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "due_day": {
+ "name": "due_day",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "method": {
+ "name": "method",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "last_paid_at": {
+ "name": "last_paid_at",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": false,
+ "autoincrement": false
+ },
+ "payments": {
+ "name": "payments",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": 0
+ },
+ "created_at": {
+ "name": "created_at",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": "CURRENT_TIMESTAMP"
+ },
+ "updated_at": {
+ "name": "updated_at",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": "CURRENT_TIMESTAMP"
+ }
+ },
+ "indexes": {
+ "debts_vault_id_idx": {
+ "name": "debts_vault_id_idx",
+ "columns": [
+ "vault_id"
+ ],
+ "isUnique": false
+ }
+ },
+ "foreignKeys": {
+ "debts_vault_id_vaults_id_fk": {
+ "name": "debts_vault_id_vaults_id_fk",
+ "tableFrom": "debts",
+ "tableTo": "vaults",
+ "columnsFrom": [
+ "vault_id"
+ ],
+ "columnsTo": [
+ "id"
+ ],
+ "onDelete": "cascade",
+ "onUpdate": "no action"
+ }
+ },
+ "compositePrimaryKeys": {},
+ "uniqueConstraints": {},
+ "checkConstraints": {}
+ },
+ "payment_records": {
+ "name": "payment_records",
+ "columns": {
+ "id": {
+ "name": "id",
+ "type": "text",
+ "primaryKey": true,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "vault_id": {
+ "name": "vault_id",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "debt_id": {
+ "name": "debt_id",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "scheduled_date": {
+ "name": "scheduled_date",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": false,
+ "autoincrement": false
+ },
+ "confirmed_at": {
+ "name": "confirmed_at",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "cash_payment": {
+ "name": "cash_payment",
+ "type": "real",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "new_balance": {
+ "name": "new_balance",
+ "type": "real",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "source": {
+ "name": "source",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": "'self_report'"
+ },
+ "created_at": {
+ "name": "created_at",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": "CURRENT_TIMESTAMP"
+ }
+ },
+ "indexes": {
+ "payments_vault_id_idx": {
+ "name": "payments_vault_id_idx",
+ "columns": [
+ "vault_id"
+ ],
+ "isUnique": false
+ },
+ "payments_debt_id_idx": {
+ "name": "payments_debt_id_idx",
+ "columns": [
+ "debt_id"
+ ],
+ "isUnique": false
+ }
+ },
+ "foreignKeys": {
+ "payment_records_vault_id_vaults_id_fk": {
+ "name": "payment_records_vault_id_vaults_id_fk",
+ "tableFrom": "payment_records",
+ "tableTo": "vaults",
+ "columnsFrom": [
+ "vault_id"
+ ],
+ "columnsTo": [
+ "id"
+ ],
+ "onDelete": "cascade",
+ "onUpdate": "no action"
+ },
+ "payment_records_debt_id_debts_id_fk": {
+ "name": "payment_records_debt_id_debts_id_fk",
+ "tableFrom": "payment_records",
+ "tableTo": "debts",
+ "columnsFrom": [
+ "debt_id"
+ ],
+ "columnsTo": [
+ "id"
+ ],
+ "onDelete": "cascade",
+ "onUpdate": "no action"
+ }
+ },
+ "compositePrimaryKeys": {},
+ "uniqueConstraints": {},
+ "checkConstraints": {}
+ },
+ "vaults": {
+ "name": "vaults",
+ "columns": {
+ "id": {
+ "name": "id",
+ "type": "text",
+ "primaryKey": true,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "recovery_hash": {
+ "name": "recovery_hash",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "alias": {
+ "name": "alias",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "region": {
+ "name": "region",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "pressure": {
+ "name": "pressure",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": "''"
+ },
+ "position_x": {
+ "name": "position_x",
+ "type": "real",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": 47
+ },
+ "position_y": {
+ "name": "position_y",
+ "type": "real",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": 63
+ },
+ "locale": {
+ "name": "locale",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": "'zh'"
+ },
+ "country_code": {
+ "name": "country_code",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": "''"
+ },
+ "country_name": {
+ "name": "country_name",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": "''"
+ },
+ "display_currency": {
+ "name": "display_currency",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": "'CNY'"
+ },
+ "monthly_income": {
+ "name": "monthly_income",
+ "type": "real",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": 0
+ },
+ "discovery_consent": {
+ "name": "discovery_consent",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": false
+ },
+ "created_at": {
+ "name": "created_at",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": "CURRENT_TIMESTAMP"
+ },
+ "updated_at": {
+ "name": "updated_at",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": "CURRENT_TIMESTAMP"
+ }
+ },
+ "indexes": {
+ "vaults_recovery_hash_unique": {
+ "name": "vaults_recovery_hash_unique",
+ "columns": [
+ "recovery_hash"
+ ],
+ "isUnique": true
+ }
+ },
+ "foreignKeys": {},
+ "compositePrimaryKeys": {},
+ "uniqueConstraints": {},
+ "checkConstraints": {}
+ },
+ "world_category_candidates": {
+ "name": "world_category_candidates",
+ "columns": {
+ "id": {
+ "name": "id",
+ "type": "text",
+ "primaryKey": true,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "canonical_key": {
+ "name": "canonical_key",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "parent_kind": {
+ "name": "parent_kind",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": "'other'"
+ },
+ "name_zh": {
+ "name": "name_zh",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "name_en": {
+ "name": "name_en",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "description_zh": {
+ "name": "description_zh",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": "''"
+ },
+ "description_en": {
+ "name": "description_en",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": "''"
+ },
+ "status": {
+ "name": "status",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": "'candidate'"
+ },
+ "stage": {
+ "name": "stage",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": 0
+ },
+ "confidence": {
+ "name": "confidence",
+ "type": "real",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": 0
+ },
+ "unique_vaults": {
+ "name": "unique_vaults",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": 0
+ },
+ "region_count": {
+ "name": "region_count",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": 0
+ },
+ "mention_count": {
+ "name": "mention_count",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": 0
+ },
+ "emergence_score": {
+ "name": "emergence_score",
+ "type": "real",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": 0
+ },
+ "weight_profile_id": {
+ "name": "weight_profile_id",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": false,
+ "autoincrement": false
+ },
+ "merged_into_id": {
+ "name": "merged_into_id",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": false,
+ "autoincrement": false
+ },
+ "proposed_at": {
+ "name": "proposed_at",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": "CURRENT_TIMESTAMP"
+ },
+ "reviewed_at": {
+ "name": "reviewed_at",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": false,
+ "autoincrement": false
+ },
+ "published_at": {
+ "name": "published_at",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": false,
+ "autoincrement": false
+ },
+ "updated_at": {
+ "name": "updated_at",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": "CURRENT_TIMESTAMP"
+ }
+ },
+ "indexes": {
+ "world_category_candidates_canonical_key_unique": {
+ "name": "world_category_candidates_canonical_key_unique",
+ "columns": [
+ "canonical_key"
+ ],
+ "isUnique": true
+ },
+ "world_candidates_status_idx": {
+ "name": "world_candidates_status_idx",
+ "columns": [
+ "status"
+ ],
+ "isUnique": false
+ },
+ "world_candidates_score_idx": {
+ "name": "world_candidates_score_idx",
+ "columns": [
+ "emergence_score"
+ ],
+ "isUnique": false
+ }
+ },
+ "foreignKeys": {
+ "world_category_candidates_weight_profile_id_world_weight_profiles_id_fk": {
+ "name": "world_category_candidates_weight_profile_id_world_weight_profiles_id_fk",
+ "tableFrom": "world_category_candidates",
+ "tableTo": "world_weight_profiles",
+ "columnsFrom": [
+ "weight_profile_id"
+ ],
+ "columnsTo": [
+ "id"
+ ],
+ "onDelete": "no action",
+ "onUpdate": "no action"
+ }
+ },
+ "compositePrimaryKeys": {},
+ "uniqueConstraints": {},
+ "checkConstraints": {}
+ },
+ "world_growth_events": {
+ "name": "world_growth_events",
+ "columns": {
+ "id": {
+ "name": "id",
+ "type": "text",
+ "primaryKey": true,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "candidate_id": {
+ "name": "candidate_id",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "event_type": {
+ "name": "event_type",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "from_stage": {
+ "name": "from_stage",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": false,
+ "autoincrement": false
+ },
+ "to_stage": {
+ "name": "to_stage",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": false,
+ "autoincrement": false
+ },
+ "actor_type": {
+ "name": "actor_type",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": "'system'"
+ },
+ "weight_profile_id": {
+ "name": "weight_profile_id",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": false,
+ "autoincrement": false
+ },
+ "evidence_json": {
+ "name": "evidence_json",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": "'{}'"
+ },
+ "reason": {
+ "name": "reason",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": "''"
+ },
+ "created_at": {
+ "name": "created_at",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": "CURRENT_TIMESTAMP"
+ }
+ },
+ "indexes": {
+ "world_events_candidate_idx": {
+ "name": "world_events_candidate_idx",
+ "columns": [
+ "candidate_id"
+ ],
+ "isUnique": false
+ }
+ },
+ "foreignKeys": {
+ "world_growth_events_candidate_id_world_category_candidates_id_fk": {
+ "name": "world_growth_events_candidate_id_world_category_candidates_id_fk",
+ "tableFrom": "world_growth_events",
+ "tableTo": "world_category_candidates",
+ "columnsFrom": [
+ "candidate_id"
+ ],
+ "columnsTo": [
+ "id"
+ ],
+ "onDelete": "cascade",
+ "onUpdate": "no action"
+ },
+ "world_growth_events_weight_profile_id_world_weight_profiles_id_fk": {
+ "name": "world_growth_events_weight_profile_id_world_weight_profiles_id_fk",
+ "tableFrom": "world_growth_events",
+ "tableTo": "world_weight_profiles",
+ "columnsFrom": [
+ "weight_profile_id"
+ ],
+ "columnsTo": [
+ "id"
+ ],
+ "onDelete": "no action",
+ "onUpdate": "no action"
+ }
+ },
+ "compositePrimaryKeys": {},
+ "uniqueConstraints": {},
+ "checkConstraints": {}
+ },
+ "world_signal_assignments": {
+ "name": "world_signal_assignments",
+ "columns": {
+ "id": {
+ "name": "id",
+ "type": "text",
+ "primaryKey": true,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "vault_id": {
+ "name": "vault_id",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "debt_id": {
+ "name": "debt_id",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "candidate_id": {
+ "name": "candidate_id",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "confidence": {
+ "name": "confidence",
+ "type": "real",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "assignment_source": {
+ "name": "assignment_source",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": "'ai'"
+ },
+ "taxonomy_version": {
+ "name": "taxonomy_version",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": 1
+ },
+ "created_at": {
+ "name": "created_at",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": "CURRENT_TIMESTAMP"
+ },
+ "updated_at": {
+ "name": "updated_at",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": "CURRENT_TIMESTAMP"
+ }
+ },
+ "indexes": {
+ "world_signal_assignments_debt_id_unique": {
+ "name": "world_signal_assignments_debt_id_unique",
+ "columns": [
+ "debt_id"
+ ],
+ "isUnique": true
+ },
+ "world_signals_vault_idx": {
+ "name": "world_signals_vault_idx",
+ "columns": [
+ "vault_id"
+ ],
+ "isUnique": false
+ },
+ "world_signals_candidate_idx": {
+ "name": "world_signals_candidate_idx",
+ "columns": [
+ "candidate_id"
+ ],
+ "isUnique": false
+ }
+ },
+ "foreignKeys": {
+ "world_signal_assignments_vault_id_vaults_id_fk": {
+ "name": "world_signal_assignments_vault_id_vaults_id_fk",
+ "tableFrom": "world_signal_assignments",
+ "tableTo": "vaults",
+ "columnsFrom": [
+ "vault_id"
+ ],
+ "columnsTo": [
+ "id"
+ ],
+ "onDelete": "cascade",
+ "onUpdate": "no action"
+ },
+ "world_signal_assignments_debt_id_debts_id_fk": {
+ "name": "world_signal_assignments_debt_id_debts_id_fk",
+ "tableFrom": "world_signal_assignments",
+ "tableTo": "debts",
+ "columnsFrom": [
+ "debt_id"
+ ],
+ "columnsTo": [
+ "id"
+ ],
+ "onDelete": "cascade",
+ "onUpdate": "no action"
+ },
+ "world_signal_assignments_candidate_id_world_category_candidates_id_fk": {
+ "name": "world_signal_assignments_candidate_id_world_category_candidates_id_fk",
+ "tableFrom": "world_signal_assignments",
+ "tableTo": "world_category_candidates",
+ "columnsFrom": [
+ "candidate_id"
+ ],
+ "columnsTo": [
+ "id"
+ ],
+ "onDelete": "cascade",
+ "onUpdate": "no action"
+ }
+ },
+ "compositePrimaryKeys": {},
+ "uniqueConstraints": {},
+ "checkConstraints": {}
+ },
+ "world_weight_profiles": {
+ "name": "world_weight_profiles",
+ "columns": {
+ "id": {
+ "name": "id",
+ "type": "text",
+ "primaryKey": true,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "version": {
+ "name": "version",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "status": {
+ "name": "status",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": "'draft'"
+ },
+ "frequency_weight": {
+ "name": "frequency_weight",
+ "type": "real",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "growth_weight": {
+ "name": "growth_weight",
+ "type": "real",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "geography_weight": {
+ "name": "geography_weight",
+ "type": "real",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "recurrence_weight": {
+ "name": "recurrence_weight",
+ "type": "real",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "connection_weight": {
+ "name": "connection_weight",
+ "type": "real",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "quality_weight": {
+ "name": "quality_weight",
+ "type": "real",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "proposed_by": {
+ "name": "proposed_by",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": "'human'"
+ },
+ "model_ref": {
+ "name": "model_ref",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": false,
+ "autoincrement": false
+ },
+ "rationale": {
+ "name": "rationale",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": "''"
+ },
+ "created_at": {
+ "name": "created_at",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": "CURRENT_TIMESTAMP"
+ },
+ "activated_at": {
+ "name": "activated_at",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": false,
+ "autoincrement": false
+ }
+ },
+ "indexes": {
+ "world_weight_profiles_version_unique": {
+ "name": "world_weight_profiles_version_unique",
+ "columns": [
+ "version"
+ ],
+ "isUnique": true
+ }
+ },
+ "foreignKeys": {},
+ "compositePrimaryKeys": {},
+ "uniqueConstraints": {},
+ "checkConstraints": {}
+ }
+ },
+ "views": {},
+ "enums": {},
+ "_meta": {
+ "schemas": {},
+ "tables": {},
+ "columns": {}
+ },
+ "internal": {
+ "indexes": {}
+ }
+}
\ No newline at end of file
diff --git a/drizzle/meta/0003_snapshot.json b/drizzle/meta/0003_snapshot.json
new file mode 100644
index 0000000..be508dc
--- /dev/null
+++ b/drizzle/meta/0003_snapshot.json
@@ -0,0 +1,986 @@
+{
+ "version": "6",
+ "dialect": "sqlite",
+ "id": "5ba2e27d-bf6a-4613-b6a6-02d294a27b32",
+ "prevId": "00b74bfb-5770-4d51-bb75-9527e61e1657",
+ "tables": {
+ "debts": {
+ "name": "debts",
+ "columns": {
+ "id": {
+ "name": "id",
+ "type": "text",
+ "primaryKey": true,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "vault_id": {
+ "name": "vault_id",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "kind": {
+ "name": "kind",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "custom_label": {
+ "name": "custom_label",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": false,
+ "autoincrement": false
+ },
+ "currency": {
+ "name": "currency",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "original": {
+ "name": "original",
+ "type": "real",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "balance": {
+ "name": "balance",
+ "type": "real",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "monthly": {
+ "name": "monthly",
+ "type": "real",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "due_day": {
+ "name": "due_day",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "method": {
+ "name": "method",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "last_paid_at": {
+ "name": "last_paid_at",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": false,
+ "autoincrement": false
+ },
+ "payments": {
+ "name": "payments",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": 0
+ },
+ "created_at": {
+ "name": "created_at",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": "CURRENT_TIMESTAMP"
+ },
+ "updated_at": {
+ "name": "updated_at",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": "CURRENT_TIMESTAMP"
+ }
+ },
+ "indexes": {
+ "debts_vault_id_idx": {
+ "name": "debts_vault_id_idx",
+ "columns": [
+ "vault_id"
+ ],
+ "isUnique": false
+ }
+ },
+ "foreignKeys": {
+ "debts_vault_id_vaults_id_fk": {
+ "name": "debts_vault_id_vaults_id_fk",
+ "tableFrom": "debts",
+ "tableTo": "vaults",
+ "columnsFrom": [
+ "vault_id"
+ ],
+ "columnsTo": [
+ "id"
+ ],
+ "onDelete": "cascade",
+ "onUpdate": "no action"
+ }
+ },
+ "compositePrimaryKeys": {},
+ "uniqueConstraints": {},
+ "checkConstraints": {}
+ },
+ "payment_records": {
+ "name": "payment_records",
+ "columns": {
+ "id": {
+ "name": "id",
+ "type": "text",
+ "primaryKey": true,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "vault_id": {
+ "name": "vault_id",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "debt_id": {
+ "name": "debt_id",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "scheduled_date": {
+ "name": "scheduled_date",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": false,
+ "autoincrement": false
+ },
+ "confirmed_at": {
+ "name": "confirmed_at",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "cash_payment": {
+ "name": "cash_payment",
+ "type": "real",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "new_balance": {
+ "name": "new_balance",
+ "type": "real",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "source": {
+ "name": "source",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": "'self_report'"
+ },
+ "created_at": {
+ "name": "created_at",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": "CURRENT_TIMESTAMP"
+ }
+ },
+ "indexes": {
+ "payments_vault_id_idx": {
+ "name": "payments_vault_id_idx",
+ "columns": [
+ "vault_id"
+ ],
+ "isUnique": false
+ },
+ "payments_debt_id_idx": {
+ "name": "payments_debt_id_idx",
+ "columns": [
+ "debt_id"
+ ],
+ "isUnique": false
+ }
+ },
+ "foreignKeys": {
+ "payment_records_vault_id_vaults_id_fk": {
+ "name": "payment_records_vault_id_vaults_id_fk",
+ "tableFrom": "payment_records",
+ "tableTo": "vaults",
+ "columnsFrom": [
+ "vault_id"
+ ],
+ "columnsTo": [
+ "id"
+ ],
+ "onDelete": "cascade",
+ "onUpdate": "no action"
+ },
+ "payment_records_debt_id_debts_id_fk": {
+ "name": "payment_records_debt_id_debts_id_fk",
+ "tableFrom": "payment_records",
+ "tableTo": "debts",
+ "columnsFrom": [
+ "debt_id"
+ ],
+ "columnsTo": [
+ "id"
+ ],
+ "onDelete": "cascade",
+ "onUpdate": "no action"
+ }
+ },
+ "compositePrimaryKeys": {},
+ "uniqueConstraints": {},
+ "checkConstraints": {}
+ },
+ "vaults": {
+ "name": "vaults",
+ "columns": {
+ "id": {
+ "name": "id",
+ "type": "text",
+ "primaryKey": true,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "recovery_hash": {
+ "name": "recovery_hash",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "alias": {
+ "name": "alias",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "region": {
+ "name": "region",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "pressure": {
+ "name": "pressure",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": "''"
+ },
+ "position_x": {
+ "name": "position_x",
+ "type": "real",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": 47
+ },
+ "position_y": {
+ "name": "position_y",
+ "type": "real",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": 63
+ },
+ "locale": {
+ "name": "locale",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": "'zh'"
+ },
+ "country_code": {
+ "name": "country_code",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": "''"
+ },
+ "country_name": {
+ "name": "country_name",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": "''"
+ },
+ "display_currency": {
+ "name": "display_currency",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": "'CNY'"
+ },
+ "monthly_income": {
+ "name": "monthly_income",
+ "type": "real",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": 0
+ },
+ "monthly_expenses": {
+ "name": "monthly_expenses",
+ "type": "real",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": 0
+ },
+ "discovery_consent": {
+ "name": "discovery_consent",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": false
+ },
+ "created_at": {
+ "name": "created_at",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": "CURRENT_TIMESTAMP"
+ },
+ "updated_at": {
+ "name": "updated_at",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": "CURRENT_TIMESTAMP"
+ }
+ },
+ "indexes": {
+ "vaults_recovery_hash_unique": {
+ "name": "vaults_recovery_hash_unique",
+ "columns": [
+ "recovery_hash"
+ ],
+ "isUnique": true
+ }
+ },
+ "foreignKeys": {},
+ "compositePrimaryKeys": {},
+ "uniqueConstraints": {},
+ "checkConstraints": {}
+ },
+ "world_category_candidates": {
+ "name": "world_category_candidates",
+ "columns": {
+ "id": {
+ "name": "id",
+ "type": "text",
+ "primaryKey": true,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "canonical_key": {
+ "name": "canonical_key",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "parent_kind": {
+ "name": "parent_kind",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": "'other'"
+ },
+ "name_zh": {
+ "name": "name_zh",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "name_en": {
+ "name": "name_en",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "description_zh": {
+ "name": "description_zh",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": "''"
+ },
+ "description_en": {
+ "name": "description_en",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": "''"
+ },
+ "status": {
+ "name": "status",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": "'candidate'"
+ },
+ "stage": {
+ "name": "stage",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": 0
+ },
+ "confidence": {
+ "name": "confidence",
+ "type": "real",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": 0
+ },
+ "unique_vaults": {
+ "name": "unique_vaults",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": 0
+ },
+ "region_count": {
+ "name": "region_count",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": 0
+ },
+ "mention_count": {
+ "name": "mention_count",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": 0
+ },
+ "emergence_score": {
+ "name": "emergence_score",
+ "type": "real",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": 0
+ },
+ "weight_profile_id": {
+ "name": "weight_profile_id",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": false,
+ "autoincrement": false
+ },
+ "merged_into_id": {
+ "name": "merged_into_id",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": false,
+ "autoincrement": false
+ },
+ "proposed_at": {
+ "name": "proposed_at",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": "CURRENT_TIMESTAMP"
+ },
+ "reviewed_at": {
+ "name": "reviewed_at",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": false,
+ "autoincrement": false
+ },
+ "published_at": {
+ "name": "published_at",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": false,
+ "autoincrement": false
+ },
+ "updated_at": {
+ "name": "updated_at",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": "CURRENT_TIMESTAMP"
+ }
+ },
+ "indexes": {
+ "world_category_candidates_canonical_key_unique": {
+ "name": "world_category_candidates_canonical_key_unique",
+ "columns": [
+ "canonical_key"
+ ],
+ "isUnique": true
+ },
+ "world_candidates_status_idx": {
+ "name": "world_candidates_status_idx",
+ "columns": [
+ "status"
+ ],
+ "isUnique": false
+ },
+ "world_candidates_score_idx": {
+ "name": "world_candidates_score_idx",
+ "columns": [
+ "emergence_score"
+ ],
+ "isUnique": false
+ }
+ },
+ "foreignKeys": {
+ "world_category_candidates_weight_profile_id_world_weight_profiles_id_fk": {
+ "name": "world_category_candidates_weight_profile_id_world_weight_profiles_id_fk",
+ "tableFrom": "world_category_candidates",
+ "tableTo": "world_weight_profiles",
+ "columnsFrom": [
+ "weight_profile_id"
+ ],
+ "columnsTo": [
+ "id"
+ ],
+ "onDelete": "no action",
+ "onUpdate": "no action"
+ }
+ },
+ "compositePrimaryKeys": {},
+ "uniqueConstraints": {},
+ "checkConstraints": {}
+ },
+ "world_growth_events": {
+ "name": "world_growth_events",
+ "columns": {
+ "id": {
+ "name": "id",
+ "type": "text",
+ "primaryKey": true,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "candidate_id": {
+ "name": "candidate_id",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "event_type": {
+ "name": "event_type",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "from_stage": {
+ "name": "from_stage",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": false,
+ "autoincrement": false
+ },
+ "to_stage": {
+ "name": "to_stage",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": false,
+ "autoincrement": false
+ },
+ "actor_type": {
+ "name": "actor_type",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": "'system'"
+ },
+ "weight_profile_id": {
+ "name": "weight_profile_id",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": false,
+ "autoincrement": false
+ },
+ "evidence_json": {
+ "name": "evidence_json",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": "'{}'"
+ },
+ "reason": {
+ "name": "reason",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": "''"
+ },
+ "created_at": {
+ "name": "created_at",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": "CURRENT_TIMESTAMP"
+ }
+ },
+ "indexes": {
+ "world_events_candidate_idx": {
+ "name": "world_events_candidate_idx",
+ "columns": [
+ "candidate_id"
+ ],
+ "isUnique": false
+ }
+ },
+ "foreignKeys": {
+ "world_growth_events_candidate_id_world_category_candidates_id_fk": {
+ "name": "world_growth_events_candidate_id_world_category_candidates_id_fk",
+ "tableFrom": "world_growth_events",
+ "tableTo": "world_category_candidates",
+ "columnsFrom": [
+ "candidate_id"
+ ],
+ "columnsTo": [
+ "id"
+ ],
+ "onDelete": "cascade",
+ "onUpdate": "no action"
+ },
+ "world_growth_events_weight_profile_id_world_weight_profiles_id_fk": {
+ "name": "world_growth_events_weight_profile_id_world_weight_profiles_id_fk",
+ "tableFrom": "world_growth_events",
+ "tableTo": "world_weight_profiles",
+ "columnsFrom": [
+ "weight_profile_id"
+ ],
+ "columnsTo": [
+ "id"
+ ],
+ "onDelete": "no action",
+ "onUpdate": "no action"
+ }
+ },
+ "compositePrimaryKeys": {},
+ "uniqueConstraints": {},
+ "checkConstraints": {}
+ },
+ "world_signal_assignments": {
+ "name": "world_signal_assignments",
+ "columns": {
+ "id": {
+ "name": "id",
+ "type": "text",
+ "primaryKey": true,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "vault_id": {
+ "name": "vault_id",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "debt_id": {
+ "name": "debt_id",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "candidate_id": {
+ "name": "candidate_id",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "confidence": {
+ "name": "confidence",
+ "type": "real",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "assignment_source": {
+ "name": "assignment_source",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": "'ai'"
+ },
+ "taxonomy_version": {
+ "name": "taxonomy_version",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": 1
+ },
+ "created_at": {
+ "name": "created_at",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": "CURRENT_TIMESTAMP"
+ },
+ "updated_at": {
+ "name": "updated_at",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": "CURRENT_TIMESTAMP"
+ }
+ },
+ "indexes": {
+ "world_signal_assignments_debt_id_unique": {
+ "name": "world_signal_assignments_debt_id_unique",
+ "columns": [
+ "debt_id"
+ ],
+ "isUnique": true
+ },
+ "world_signals_vault_idx": {
+ "name": "world_signals_vault_idx",
+ "columns": [
+ "vault_id"
+ ],
+ "isUnique": false
+ },
+ "world_signals_candidate_idx": {
+ "name": "world_signals_candidate_idx",
+ "columns": [
+ "candidate_id"
+ ],
+ "isUnique": false
+ }
+ },
+ "foreignKeys": {
+ "world_signal_assignments_vault_id_vaults_id_fk": {
+ "name": "world_signal_assignments_vault_id_vaults_id_fk",
+ "tableFrom": "world_signal_assignments",
+ "tableTo": "vaults",
+ "columnsFrom": [
+ "vault_id"
+ ],
+ "columnsTo": [
+ "id"
+ ],
+ "onDelete": "cascade",
+ "onUpdate": "no action"
+ },
+ "world_signal_assignments_debt_id_debts_id_fk": {
+ "name": "world_signal_assignments_debt_id_debts_id_fk",
+ "tableFrom": "world_signal_assignments",
+ "tableTo": "debts",
+ "columnsFrom": [
+ "debt_id"
+ ],
+ "columnsTo": [
+ "id"
+ ],
+ "onDelete": "cascade",
+ "onUpdate": "no action"
+ },
+ "world_signal_assignments_candidate_id_world_category_candidates_id_fk": {
+ "name": "world_signal_assignments_candidate_id_world_category_candidates_id_fk",
+ "tableFrom": "world_signal_assignments",
+ "tableTo": "world_category_candidates",
+ "columnsFrom": [
+ "candidate_id"
+ ],
+ "columnsTo": [
+ "id"
+ ],
+ "onDelete": "cascade",
+ "onUpdate": "no action"
+ }
+ },
+ "compositePrimaryKeys": {},
+ "uniqueConstraints": {},
+ "checkConstraints": {}
+ },
+ "world_weight_profiles": {
+ "name": "world_weight_profiles",
+ "columns": {
+ "id": {
+ "name": "id",
+ "type": "text",
+ "primaryKey": true,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "version": {
+ "name": "version",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "status": {
+ "name": "status",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": "'draft'"
+ },
+ "frequency_weight": {
+ "name": "frequency_weight",
+ "type": "real",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "growth_weight": {
+ "name": "growth_weight",
+ "type": "real",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "geography_weight": {
+ "name": "geography_weight",
+ "type": "real",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "recurrence_weight": {
+ "name": "recurrence_weight",
+ "type": "real",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "connection_weight": {
+ "name": "connection_weight",
+ "type": "real",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "quality_weight": {
+ "name": "quality_weight",
+ "type": "real",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "proposed_by": {
+ "name": "proposed_by",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": "'human'"
+ },
+ "model_ref": {
+ "name": "model_ref",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": false,
+ "autoincrement": false
+ },
+ "rationale": {
+ "name": "rationale",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": "''"
+ },
+ "created_at": {
+ "name": "created_at",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": "CURRENT_TIMESTAMP"
+ },
+ "activated_at": {
+ "name": "activated_at",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": false,
+ "autoincrement": false
+ }
+ },
+ "indexes": {
+ "world_weight_profiles_version_unique": {
+ "name": "world_weight_profiles_version_unique",
+ "columns": [
+ "version"
+ ],
+ "isUnique": true
+ }
+ },
+ "foreignKeys": {},
+ "compositePrimaryKeys": {},
+ "uniqueConstraints": {},
+ "checkConstraints": {}
+ }
+ },
+ "views": {},
+ "enums": {},
+ "_meta": {
+ "schemas": {},
+ "tables": {},
+ "columns": {}
+ },
+ "internal": {
+ "indexes": {}
+ }
+}
\ No newline at end of file
diff --git a/drizzle/meta/0004_snapshot.json b/drizzle/meta/0004_snapshot.json
new file mode 100644
index 0000000..5a3a42d
--- /dev/null
+++ b/drizzle/meta/0004_snapshot.json
@@ -0,0 +1,994 @@
+{
+ "version": "6",
+ "dialect": "sqlite",
+ "id": "01a1d274-aad5-4013-9b0f-edb76af8247a",
+ "prevId": "5ba2e27d-bf6a-4613-b6a6-02d294a27b32",
+ "tables": {
+ "debts": {
+ "name": "debts",
+ "columns": {
+ "id": {
+ "name": "id",
+ "type": "text",
+ "primaryKey": true,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "vault_id": {
+ "name": "vault_id",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "kind": {
+ "name": "kind",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "custom_label": {
+ "name": "custom_label",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": false,
+ "autoincrement": false
+ },
+ "currency": {
+ "name": "currency",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "original": {
+ "name": "original",
+ "type": "real",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "balance": {
+ "name": "balance",
+ "type": "real",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "monthly": {
+ "name": "monthly",
+ "type": "real",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "due_day": {
+ "name": "due_day",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "method": {
+ "name": "method",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "sharing_mode": {
+ "name": "sharing_mode",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": "'private'"
+ },
+ "last_paid_at": {
+ "name": "last_paid_at",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": false,
+ "autoincrement": false
+ },
+ "payments": {
+ "name": "payments",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": 0
+ },
+ "created_at": {
+ "name": "created_at",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": "CURRENT_TIMESTAMP"
+ },
+ "updated_at": {
+ "name": "updated_at",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": "CURRENT_TIMESTAMP"
+ }
+ },
+ "indexes": {
+ "debts_vault_id_idx": {
+ "name": "debts_vault_id_idx",
+ "columns": [
+ "vault_id"
+ ],
+ "isUnique": false
+ }
+ },
+ "foreignKeys": {
+ "debts_vault_id_vaults_id_fk": {
+ "name": "debts_vault_id_vaults_id_fk",
+ "tableFrom": "debts",
+ "tableTo": "vaults",
+ "columnsFrom": [
+ "vault_id"
+ ],
+ "columnsTo": [
+ "id"
+ ],
+ "onDelete": "cascade",
+ "onUpdate": "no action"
+ }
+ },
+ "compositePrimaryKeys": {},
+ "uniqueConstraints": {},
+ "checkConstraints": {}
+ },
+ "payment_records": {
+ "name": "payment_records",
+ "columns": {
+ "id": {
+ "name": "id",
+ "type": "text",
+ "primaryKey": true,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "vault_id": {
+ "name": "vault_id",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "debt_id": {
+ "name": "debt_id",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "scheduled_date": {
+ "name": "scheduled_date",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": false,
+ "autoincrement": false
+ },
+ "confirmed_at": {
+ "name": "confirmed_at",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "cash_payment": {
+ "name": "cash_payment",
+ "type": "real",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "new_balance": {
+ "name": "new_balance",
+ "type": "real",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "source": {
+ "name": "source",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": "'self_report'"
+ },
+ "created_at": {
+ "name": "created_at",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": "CURRENT_TIMESTAMP"
+ }
+ },
+ "indexes": {
+ "payments_vault_id_idx": {
+ "name": "payments_vault_id_idx",
+ "columns": [
+ "vault_id"
+ ],
+ "isUnique": false
+ },
+ "payments_debt_id_idx": {
+ "name": "payments_debt_id_idx",
+ "columns": [
+ "debt_id"
+ ],
+ "isUnique": false
+ }
+ },
+ "foreignKeys": {
+ "payment_records_vault_id_vaults_id_fk": {
+ "name": "payment_records_vault_id_vaults_id_fk",
+ "tableFrom": "payment_records",
+ "tableTo": "vaults",
+ "columnsFrom": [
+ "vault_id"
+ ],
+ "columnsTo": [
+ "id"
+ ],
+ "onDelete": "cascade",
+ "onUpdate": "no action"
+ },
+ "payment_records_debt_id_debts_id_fk": {
+ "name": "payment_records_debt_id_debts_id_fk",
+ "tableFrom": "payment_records",
+ "tableTo": "debts",
+ "columnsFrom": [
+ "debt_id"
+ ],
+ "columnsTo": [
+ "id"
+ ],
+ "onDelete": "cascade",
+ "onUpdate": "no action"
+ }
+ },
+ "compositePrimaryKeys": {},
+ "uniqueConstraints": {},
+ "checkConstraints": {}
+ },
+ "vaults": {
+ "name": "vaults",
+ "columns": {
+ "id": {
+ "name": "id",
+ "type": "text",
+ "primaryKey": true,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "recovery_hash": {
+ "name": "recovery_hash",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "alias": {
+ "name": "alias",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "region": {
+ "name": "region",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "pressure": {
+ "name": "pressure",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": "''"
+ },
+ "position_x": {
+ "name": "position_x",
+ "type": "real",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": 47
+ },
+ "position_y": {
+ "name": "position_y",
+ "type": "real",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": 63
+ },
+ "locale": {
+ "name": "locale",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": "'zh'"
+ },
+ "country_code": {
+ "name": "country_code",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": "''"
+ },
+ "country_name": {
+ "name": "country_name",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": "''"
+ },
+ "display_currency": {
+ "name": "display_currency",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": "'CNY'"
+ },
+ "monthly_income": {
+ "name": "monthly_income",
+ "type": "real",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": 0
+ },
+ "monthly_expenses": {
+ "name": "monthly_expenses",
+ "type": "real",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": 0
+ },
+ "discovery_consent": {
+ "name": "discovery_consent",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": false
+ },
+ "created_at": {
+ "name": "created_at",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": "CURRENT_TIMESTAMP"
+ },
+ "updated_at": {
+ "name": "updated_at",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": "CURRENT_TIMESTAMP"
+ }
+ },
+ "indexes": {
+ "vaults_recovery_hash_unique": {
+ "name": "vaults_recovery_hash_unique",
+ "columns": [
+ "recovery_hash"
+ ],
+ "isUnique": true
+ }
+ },
+ "foreignKeys": {},
+ "compositePrimaryKeys": {},
+ "uniqueConstraints": {},
+ "checkConstraints": {}
+ },
+ "world_category_candidates": {
+ "name": "world_category_candidates",
+ "columns": {
+ "id": {
+ "name": "id",
+ "type": "text",
+ "primaryKey": true,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "canonical_key": {
+ "name": "canonical_key",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "parent_kind": {
+ "name": "parent_kind",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": "'other'"
+ },
+ "name_zh": {
+ "name": "name_zh",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "name_en": {
+ "name": "name_en",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "description_zh": {
+ "name": "description_zh",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": "''"
+ },
+ "description_en": {
+ "name": "description_en",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": "''"
+ },
+ "status": {
+ "name": "status",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": "'candidate'"
+ },
+ "stage": {
+ "name": "stage",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": 0
+ },
+ "confidence": {
+ "name": "confidence",
+ "type": "real",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": 0
+ },
+ "unique_vaults": {
+ "name": "unique_vaults",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": 0
+ },
+ "region_count": {
+ "name": "region_count",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": 0
+ },
+ "mention_count": {
+ "name": "mention_count",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": 0
+ },
+ "emergence_score": {
+ "name": "emergence_score",
+ "type": "real",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": 0
+ },
+ "weight_profile_id": {
+ "name": "weight_profile_id",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": false,
+ "autoincrement": false
+ },
+ "merged_into_id": {
+ "name": "merged_into_id",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": false,
+ "autoincrement": false
+ },
+ "proposed_at": {
+ "name": "proposed_at",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": "CURRENT_TIMESTAMP"
+ },
+ "reviewed_at": {
+ "name": "reviewed_at",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": false,
+ "autoincrement": false
+ },
+ "published_at": {
+ "name": "published_at",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": false,
+ "autoincrement": false
+ },
+ "updated_at": {
+ "name": "updated_at",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": "CURRENT_TIMESTAMP"
+ }
+ },
+ "indexes": {
+ "world_category_candidates_canonical_key_unique": {
+ "name": "world_category_candidates_canonical_key_unique",
+ "columns": [
+ "canonical_key"
+ ],
+ "isUnique": true
+ },
+ "world_candidates_status_idx": {
+ "name": "world_candidates_status_idx",
+ "columns": [
+ "status"
+ ],
+ "isUnique": false
+ },
+ "world_candidates_score_idx": {
+ "name": "world_candidates_score_idx",
+ "columns": [
+ "emergence_score"
+ ],
+ "isUnique": false
+ }
+ },
+ "foreignKeys": {
+ "world_category_candidates_weight_profile_id_world_weight_profiles_id_fk": {
+ "name": "world_category_candidates_weight_profile_id_world_weight_profiles_id_fk",
+ "tableFrom": "world_category_candidates",
+ "tableTo": "world_weight_profiles",
+ "columnsFrom": [
+ "weight_profile_id"
+ ],
+ "columnsTo": [
+ "id"
+ ],
+ "onDelete": "no action",
+ "onUpdate": "no action"
+ }
+ },
+ "compositePrimaryKeys": {},
+ "uniqueConstraints": {},
+ "checkConstraints": {}
+ },
+ "world_growth_events": {
+ "name": "world_growth_events",
+ "columns": {
+ "id": {
+ "name": "id",
+ "type": "text",
+ "primaryKey": true,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "candidate_id": {
+ "name": "candidate_id",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "event_type": {
+ "name": "event_type",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "from_stage": {
+ "name": "from_stage",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": false,
+ "autoincrement": false
+ },
+ "to_stage": {
+ "name": "to_stage",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": false,
+ "autoincrement": false
+ },
+ "actor_type": {
+ "name": "actor_type",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": "'system'"
+ },
+ "weight_profile_id": {
+ "name": "weight_profile_id",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": false,
+ "autoincrement": false
+ },
+ "evidence_json": {
+ "name": "evidence_json",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": "'{}'"
+ },
+ "reason": {
+ "name": "reason",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": "''"
+ },
+ "created_at": {
+ "name": "created_at",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": "CURRENT_TIMESTAMP"
+ }
+ },
+ "indexes": {
+ "world_events_candidate_idx": {
+ "name": "world_events_candidate_idx",
+ "columns": [
+ "candidate_id"
+ ],
+ "isUnique": false
+ }
+ },
+ "foreignKeys": {
+ "world_growth_events_candidate_id_world_category_candidates_id_fk": {
+ "name": "world_growth_events_candidate_id_world_category_candidates_id_fk",
+ "tableFrom": "world_growth_events",
+ "tableTo": "world_category_candidates",
+ "columnsFrom": [
+ "candidate_id"
+ ],
+ "columnsTo": [
+ "id"
+ ],
+ "onDelete": "cascade",
+ "onUpdate": "no action"
+ },
+ "world_growth_events_weight_profile_id_world_weight_profiles_id_fk": {
+ "name": "world_growth_events_weight_profile_id_world_weight_profiles_id_fk",
+ "tableFrom": "world_growth_events",
+ "tableTo": "world_weight_profiles",
+ "columnsFrom": [
+ "weight_profile_id"
+ ],
+ "columnsTo": [
+ "id"
+ ],
+ "onDelete": "no action",
+ "onUpdate": "no action"
+ }
+ },
+ "compositePrimaryKeys": {},
+ "uniqueConstraints": {},
+ "checkConstraints": {}
+ },
+ "world_signal_assignments": {
+ "name": "world_signal_assignments",
+ "columns": {
+ "id": {
+ "name": "id",
+ "type": "text",
+ "primaryKey": true,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "vault_id": {
+ "name": "vault_id",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "debt_id": {
+ "name": "debt_id",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "candidate_id": {
+ "name": "candidate_id",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "confidence": {
+ "name": "confidence",
+ "type": "real",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "assignment_source": {
+ "name": "assignment_source",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": "'ai'"
+ },
+ "taxonomy_version": {
+ "name": "taxonomy_version",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": 1
+ },
+ "created_at": {
+ "name": "created_at",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": "CURRENT_TIMESTAMP"
+ },
+ "updated_at": {
+ "name": "updated_at",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": "CURRENT_TIMESTAMP"
+ }
+ },
+ "indexes": {
+ "world_signal_assignments_debt_id_unique": {
+ "name": "world_signal_assignments_debt_id_unique",
+ "columns": [
+ "debt_id"
+ ],
+ "isUnique": true
+ },
+ "world_signals_vault_idx": {
+ "name": "world_signals_vault_idx",
+ "columns": [
+ "vault_id"
+ ],
+ "isUnique": false
+ },
+ "world_signals_candidate_idx": {
+ "name": "world_signals_candidate_idx",
+ "columns": [
+ "candidate_id"
+ ],
+ "isUnique": false
+ }
+ },
+ "foreignKeys": {
+ "world_signal_assignments_vault_id_vaults_id_fk": {
+ "name": "world_signal_assignments_vault_id_vaults_id_fk",
+ "tableFrom": "world_signal_assignments",
+ "tableTo": "vaults",
+ "columnsFrom": [
+ "vault_id"
+ ],
+ "columnsTo": [
+ "id"
+ ],
+ "onDelete": "cascade",
+ "onUpdate": "no action"
+ },
+ "world_signal_assignments_debt_id_debts_id_fk": {
+ "name": "world_signal_assignments_debt_id_debts_id_fk",
+ "tableFrom": "world_signal_assignments",
+ "tableTo": "debts",
+ "columnsFrom": [
+ "debt_id"
+ ],
+ "columnsTo": [
+ "id"
+ ],
+ "onDelete": "cascade",
+ "onUpdate": "no action"
+ },
+ "world_signal_assignments_candidate_id_world_category_candidates_id_fk": {
+ "name": "world_signal_assignments_candidate_id_world_category_candidates_id_fk",
+ "tableFrom": "world_signal_assignments",
+ "tableTo": "world_category_candidates",
+ "columnsFrom": [
+ "candidate_id"
+ ],
+ "columnsTo": [
+ "id"
+ ],
+ "onDelete": "cascade",
+ "onUpdate": "no action"
+ }
+ },
+ "compositePrimaryKeys": {},
+ "uniqueConstraints": {},
+ "checkConstraints": {}
+ },
+ "world_weight_profiles": {
+ "name": "world_weight_profiles",
+ "columns": {
+ "id": {
+ "name": "id",
+ "type": "text",
+ "primaryKey": true,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "version": {
+ "name": "version",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "status": {
+ "name": "status",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": "'draft'"
+ },
+ "frequency_weight": {
+ "name": "frequency_weight",
+ "type": "real",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "growth_weight": {
+ "name": "growth_weight",
+ "type": "real",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "geography_weight": {
+ "name": "geography_weight",
+ "type": "real",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "recurrence_weight": {
+ "name": "recurrence_weight",
+ "type": "real",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "connection_weight": {
+ "name": "connection_weight",
+ "type": "real",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "quality_weight": {
+ "name": "quality_weight",
+ "type": "real",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "proposed_by": {
+ "name": "proposed_by",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": "'human'"
+ },
+ "model_ref": {
+ "name": "model_ref",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": false,
+ "autoincrement": false
+ },
+ "rationale": {
+ "name": "rationale",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": "''"
+ },
+ "created_at": {
+ "name": "created_at",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": "CURRENT_TIMESTAMP"
+ },
+ "activated_at": {
+ "name": "activated_at",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": false,
+ "autoincrement": false
+ }
+ },
+ "indexes": {
+ "world_weight_profiles_version_unique": {
+ "name": "world_weight_profiles_version_unique",
+ "columns": [
+ "version"
+ ],
+ "isUnique": true
+ }
+ },
+ "foreignKeys": {},
+ "compositePrimaryKeys": {},
+ "uniqueConstraints": {},
+ "checkConstraints": {}
+ }
+ },
+ "views": {},
+ "enums": {},
+ "_meta": {
+ "schemas": {},
+ "tables": {},
+ "columns": {}
+ },
+ "internal": {
+ "indexes": {}
+ }
+}
\ No newline at end of file
diff --git a/drizzle/meta/0005_snapshot.json b/drizzle/meta/0005_snapshot.json
new file mode 100644
index 0000000..c6e5065
--- /dev/null
+++ b/drizzle/meta/0005_snapshot.json
@@ -0,0 +1,1439 @@
+{
+ "version": "6",
+ "dialect": "sqlite",
+ "id": "b2cdbeb3-108a-42a0-8079-0e52cf97e01c",
+ "prevId": "01a1d274-aad5-4013-9b0f-edb76af8247a",
+ "tables": {
+ "debts": {
+ "name": "debts",
+ "columns": {
+ "id": {
+ "name": "id",
+ "type": "text",
+ "primaryKey": true,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "vault_id": {
+ "name": "vault_id",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "kind": {
+ "name": "kind",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "custom_label": {
+ "name": "custom_label",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": false,
+ "autoincrement": false
+ },
+ "currency": {
+ "name": "currency",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "original": {
+ "name": "original",
+ "type": "real",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "balance": {
+ "name": "balance",
+ "type": "real",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "monthly": {
+ "name": "monthly",
+ "type": "real",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "due_day": {
+ "name": "due_day",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "method": {
+ "name": "method",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "sharing_mode": {
+ "name": "sharing_mode",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": "'private'"
+ },
+ "last_paid_at": {
+ "name": "last_paid_at",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": false,
+ "autoincrement": false
+ },
+ "payments": {
+ "name": "payments",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": 0
+ },
+ "created_at": {
+ "name": "created_at",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": "CURRENT_TIMESTAMP"
+ },
+ "updated_at": {
+ "name": "updated_at",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": "CURRENT_TIMESTAMP"
+ }
+ },
+ "indexes": {
+ "debts_vault_id_idx": {
+ "name": "debts_vault_id_idx",
+ "columns": [
+ "vault_id"
+ ],
+ "isUnique": false
+ }
+ },
+ "foreignKeys": {
+ "debts_vault_id_vaults_id_fk": {
+ "name": "debts_vault_id_vaults_id_fk",
+ "tableFrom": "debts",
+ "tableTo": "vaults",
+ "columnsFrom": [
+ "vault_id"
+ ],
+ "columnsTo": [
+ "id"
+ ],
+ "onDelete": "cascade",
+ "onUpdate": "no action"
+ }
+ },
+ "compositePrimaryKeys": {},
+ "uniqueConstraints": {},
+ "checkConstraints": {}
+ },
+ "lucky_income_claims": {
+ "name": "lucky_income_claims",
+ "columns": {
+ "id": {
+ "name": "id",
+ "type": "text",
+ "primaryKey": true,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "vault_id": {
+ "name": "vault_id",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "debt_id": {
+ "name": "debt_id",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "event_date": {
+ "name": "event_date",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "created_at": {
+ "name": "created_at",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": "CURRENT_TIMESTAMP"
+ }
+ },
+ "indexes": {
+ "lucky_income_vault_day_unique": {
+ "name": "lucky_income_vault_day_unique",
+ "columns": [
+ "vault_id",
+ "event_date"
+ ],
+ "isUnique": true
+ },
+ "lucky_income_debt_idx": {
+ "name": "lucky_income_debt_idx",
+ "columns": [
+ "debt_id"
+ ],
+ "isUnique": false
+ }
+ },
+ "foreignKeys": {
+ "lucky_income_claims_vault_id_vaults_id_fk": {
+ "name": "lucky_income_claims_vault_id_vaults_id_fk",
+ "tableFrom": "lucky_income_claims",
+ "tableTo": "vaults",
+ "columnsFrom": [
+ "vault_id"
+ ],
+ "columnsTo": [
+ "id"
+ ],
+ "onDelete": "cascade",
+ "onUpdate": "no action"
+ },
+ "lucky_income_claims_debt_id_debts_id_fk": {
+ "name": "lucky_income_claims_debt_id_debts_id_fk",
+ "tableFrom": "lucky_income_claims",
+ "tableTo": "debts",
+ "columnsFrom": [
+ "debt_id"
+ ],
+ "columnsTo": [
+ "id"
+ ],
+ "onDelete": "cascade",
+ "onUpdate": "no action"
+ }
+ },
+ "compositePrimaryKeys": {},
+ "uniqueConstraints": {},
+ "checkConstraints": {}
+ },
+ "payment_records": {
+ "name": "payment_records",
+ "columns": {
+ "id": {
+ "name": "id",
+ "type": "text",
+ "primaryKey": true,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "vault_id": {
+ "name": "vault_id",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "debt_id": {
+ "name": "debt_id",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "scheduled_date": {
+ "name": "scheduled_date",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": false,
+ "autoincrement": false
+ },
+ "confirmed_at": {
+ "name": "confirmed_at",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "event_date": {
+ "name": "event_date",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": false,
+ "autoincrement": false
+ },
+ "cash_payment": {
+ "name": "cash_payment",
+ "type": "real",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "new_balance": {
+ "name": "new_balance",
+ "type": "real",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "source": {
+ "name": "source",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": "'self_report'"
+ },
+ "income_type": {
+ "name": "income_type",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": false,
+ "autoincrement": false
+ },
+ "created_at": {
+ "name": "created_at",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": "CURRENT_TIMESTAMP"
+ }
+ },
+ "indexes": {
+ "payments_vault_id_idx": {
+ "name": "payments_vault_id_idx",
+ "columns": [
+ "vault_id"
+ ],
+ "isUnique": false
+ },
+ "payments_debt_id_idx": {
+ "name": "payments_debt_id_idx",
+ "columns": [
+ "debt_id"
+ ],
+ "isUnique": false
+ }
+ },
+ "foreignKeys": {
+ "payment_records_vault_id_vaults_id_fk": {
+ "name": "payment_records_vault_id_vaults_id_fk",
+ "tableFrom": "payment_records",
+ "tableTo": "vaults",
+ "columnsFrom": [
+ "vault_id"
+ ],
+ "columnsTo": [
+ "id"
+ ],
+ "onDelete": "cascade",
+ "onUpdate": "no action"
+ },
+ "payment_records_debt_id_debts_id_fk": {
+ "name": "payment_records_debt_id_debts_id_fk",
+ "tableFrom": "payment_records",
+ "tableTo": "debts",
+ "columnsFrom": [
+ "debt_id"
+ ],
+ "columnsTo": [
+ "id"
+ ],
+ "onDelete": "cascade",
+ "onUpdate": "no action"
+ }
+ },
+ "compositePrimaryKeys": {},
+ "uniqueConstraints": {},
+ "checkConstraints": {}
+ },
+ "public_stories": {
+ "name": "public_stories",
+ "columns": {
+ "id": {
+ "name": "id",
+ "type": "text",
+ "primaryKey": true,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "vault_id": {
+ "name": "vault_id",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "debt_id": {
+ "name": "debt_id",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "anonymous_name": {
+ "name": "anonymous_name",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "country_code": {
+ "name": "country_code",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": "''"
+ },
+ "debt_kind": {
+ "name": "debt_kind",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "amount_band": {
+ "name": "amount_band",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "currency": {
+ "name": "currency",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "repayment_approach": {
+ "name": "repayment_approach",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": "'other'"
+ },
+ "story_text": {
+ "name": "story_text",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "status": {
+ "name": "status",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": "'pending'"
+ },
+ "created_at": {
+ "name": "created_at",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": "CURRENT_TIMESTAMP"
+ },
+ "updated_at": {
+ "name": "updated_at",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": "CURRENT_TIMESTAMP"
+ }
+ },
+ "indexes": {
+ "public_stories_status_idx": {
+ "name": "public_stories_status_idx",
+ "columns": [
+ "status"
+ ],
+ "isUnique": false
+ },
+ "public_stories_vault_idx": {
+ "name": "public_stories_vault_idx",
+ "columns": [
+ "vault_id"
+ ],
+ "isUnique": false
+ }
+ },
+ "foreignKeys": {
+ "public_stories_vault_id_vaults_id_fk": {
+ "name": "public_stories_vault_id_vaults_id_fk",
+ "tableFrom": "public_stories",
+ "tableTo": "vaults",
+ "columnsFrom": [
+ "vault_id"
+ ],
+ "columnsTo": [
+ "id"
+ ],
+ "onDelete": "cascade",
+ "onUpdate": "no action"
+ },
+ "public_stories_debt_id_debts_id_fk": {
+ "name": "public_stories_debt_id_debts_id_fk",
+ "tableFrom": "public_stories",
+ "tableTo": "debts",
+ "columnsFrom": [
+ "debt_id"
+ ],
+ "columnsTo": [
+ "id"
+ ],
+ "onDelete": "cascade",
+ "onUpdate": "no action"
+ }
+ },
+ "compositePrimaryKeys": {},
+ "uniqueConstraints": {},
+ "checkConstraints": {}
+ },
+ "story_encouragements": {
+ "name": "story_encouragements",
+ "columns": {
+ "id": {
+ "name": "id",
+ "type": "text",
+ "primaryKey": true,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "story_id": {
+ "name": "story_id",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "vault_id": {
+ "name": "vault_id",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "created_at": {
+ "name": "created_at",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": "CURRENT_TIMESTAMP"
+ }
+ },
+ "indexes": {
+ "story_encouragement_unique": {
+ "name": "story_encouragement_unique",
+ "columns": [
+ "story_id",
+ "vault_id"
+ ],
+ "isUnique": true
+ },
+ "story_encouragement_story_idx": {
+ "name": "story_encouragement_story_idx",
+ "columns": [
+ "story_id"
+ ],
+ "isUnique": false
+ }
+ },
+ "foreignKeys": {
+ "story_encouragements_story_id_public_stories_id_fk": {
+ "name": "story_encouragements_story_id_public_stories_id_fk",
+ "tableFrom": "story_encouragements",
+ "tableTo": "public_stories",
+ "columnsFrom": [
+ "story_id"
+ ],
+ "columnsTo": [
+ "id"
+ ],
+ "onDelete": "cascade",
+ "onUpdate": "no action"
+ },
+ "story_encouragements_vault_id_vaults_id_fk": {
+ "name": "story_encouragements_vault_id_vaults_id_fk",
+ "tableFrom": "story_encouragements",
+ "tableTo": "vaults",
+ "columnsFrom": [
+ "vault_id"
+ ],
+ "columnsTo": [
+ "id"
+ ],
+ "onDelete": "cascade",
+ "onUpdate": "no action"
+ }
+ },
+ "compositePrimaryKeys": {},
+ "uniqueConstraints": {},
+ "checkConstraints": {}
+ },
+ "story_reports": {
+ "name": "story_reports",
+ "columns": {
+ "id": {
+ "name": "id",
+ "type": "text",
+ "primaryKey": true,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "story_id": {
+ "name": "story_id",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "reporter_vault_id": {
+ "name": "reporter_vault_id",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "reason": {
+ "name": "reason",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "details": {
+ "name": "details",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": "''"
+ },
+ "status": {
+ "name": "status",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": "'open'"
+ },
+ "created_at": {
+ "name": "created_at",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": "CURRENT_TIMESTAMP"
+ },
+ "resolved_at": {
+ "name": "resolved_at",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": false,
+ "autoincrement": false
+ }
+ },
+ "indexes": {
+ "story_report_unique": {
+ "name": "story_report_unique",
+ "columns": [
+ "story_id",
+ "reporter_vault_id"
+ ],
+ "isUnique": true
+ },
+ "story_reports_status_idx": {
+ "name": "story_reports_status_idx",
+ "columns": [
+ "status"
+ ],
+ "isUnique": false
+ }
+ },
+ "foreignKeys": {
+ "story_reports_story_id_public_stories_id_fk": {
+ "name": "story_reports_story_id_public_stories_id_fk",
+ "tableFrom": "story_reports",
+ "tableTo": "public_stories",
+ "columnsFrom": [
+ "story_id"
+ ],
+ "columnsTo": [
+ "id"
+ ],
+ "onDelete": "cascade",
+ "onUpdate": "no action"
+ },
+ "story_reports_reporter_vault_id_vaults_id_fk": {
+ "name": "story_reports_reporter_vault_id_vaults_id_fk",
+ "tableFrom": "story_reports",
+ "tableTo": "vaults",
+ "columnsFrom": [
+ "reporter_vault_id"
+ ],
+ "columnsTo": [
+ "id"
+ ],
+ "onDelete": "cascade",
+ "onUpdate": "no action"
+ }
+ },
+ "compositePrimaryKeys": {},
+ "uniqueConstraints": {},
+ "checkConstraints": {}
+ },
+ "vaults": {
+ "name": "vaults",
+ "columns": {
+ "id": {
+ "name": "id",
+ "type": "text",
+ "primaryKey": true,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "recovery_hash": {
+ "name": "recovery_hash",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "alias": {
+ "name": "alias",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "region": {
+ "name": "region",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "pressure": {
+ "name": "pressure",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": "''"
+ },
+ "position_x": {
+ "name": "position_x",
+ "type": "real",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": 47
+ },
+ "position_y": {
+ "name": "position_y",
+ "type": "real",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": 63
+ },
+ "locale": {
+ "name": "locale",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": "'zh'"
+ },
+ "country_code": {
+ "name": "country_code",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": "''"
+ },
+ "country_name": {
+ "name": "country_name",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": "''"
+ },
+ "display_currency": {
+ "name": "display_currency",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": "'CNY'"
+ },
+ "monthly_income": {
+ "name": "monthly_income",
+ "type": "real",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": 0
+ },
+ "monthly_expenses": {
+ "name": "monthly_expenses",
+ "type": "real",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": 0
+ },
+ "discovery_consent": {
+ "name": "discovery_consent",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": false
+ },
+ "created_at": {
+ "name": "created_at",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": "CURRENT_TIMESTAMP"
+ },
+ "updated_at": {
+ "name": "updated_at",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": "CURRENT_TIMESTAMP"
+ }
+ },
+ "indexes": {
+ "vaults_recovery_hash_unique": {
+ "name": "vaults_recovery_hash_unique",
+ "columns": [
+ "recovery_hash"
+ ],
+ "isUnique": true
+ }
+ },
+ "foreignKeys": {},
+ "compositePrimaryKeys": {},
+ "uniqueConstraints": {},
+ "checkConstraints": {}
+ },
+ "world_category_candidates": {
+ "name": "world_category_candidates",
+ "columns": {
+ "id": {
+ "name": "id",
+ "type": "text",
+ "primaryKey": true,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "canonical_key": {
+ "name": "canonical_key",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "parent_kind": {
+ "name": "parent_kind",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": "'other'"
+ },
+ "name_zh": {
+ "name": "name_zh",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "name_en": {
+ "name": "name_en",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "description_zh": {
+ "name": "description_zh",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": "''"
+ },
+ "description_en": {
+ "name": "description_en",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": "''"
+ },
+ "status": {
+ "name": "status",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": "'candidate'"
+ },
+ "stage": {
+ "name": "stage",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": 0
+ },
+ "confidence": {
+ "name": "confidence",
+ "type": "real",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": 0
+ },
+ "unique_vaults": {
+ "name": "unique_vaults",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": 0
+ },
+ "region_count": {
+ "name": "region_count",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": 0
+ },
+ "mention_count": {
+ "name": "mention_count",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": 0
+ },
+ "emergence_score": {
+ "name": "emergence_score",
+ "type": "real",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": 0
+ },
+ "weight_profile_id": {
+ "name": "weight_profile_id",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": false,
+ "autoincrement": false
+ },
+ "merged_into_id": {
+ "name": "merged_into_id",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": false,
+ "autoincrement": false
+ },
+ "proposed_at": {
+ "name": "proposed_at",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": "CURRENT_TIMESTAMP"
+ },
+ "reviewed_at": {
+ "name": "reviewed_at",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": false,
+ "autoincrement": false
+ },
+ "published_at": {
+ "name": "published_at",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": false,
+ "autoincrement": false
+ },
+ "updated_at": {
+ "name": "updated_at",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": "CURRENT_TIMESTAMP"
+ }
+ },
+ "indexes": {
+ "world_category_candidates_canonical_key_unique": {
+ "name": "world_category_candidates_canonical_key_unique",
+ "columns": [
+ "canonical_key"
+ ],
+ "isUnique": true
+ },
+ "world_candidates_status_idx": {
+ "name": "world_candidates_status_idx",
+ "columns": [
+ "status"
+ ],
+ "isUnique": false
+ },
+ "world_candidates_score_idx": {
+ "name": "world_candidates_score_idx",
+ "columns": [
+ "emergence_score"
+ ],
+ "isUnique": false
+ }
+ },
+ "foreignKeys": {
+ "world_category_candidates_weight_profile_id_world_weight_profiles_id_fk": {
+ "name": "world_category_candidates_weight_profile_id_world_weight_profiles_id_fk",
+ "tableFrom": "world_category_candidates",
+ "tableTo": "world_weight_profiles",
+ "columnsFrom": [
+ "weight_profile_id"
+ ],
+ "columnsTo": [
+ "id"
+ ],
+ "onDelete": "no action",
+ "onUpdate": "no action"
+ }
+ },
+ "compositePrimaryKeys": {},
+ "uniqueConstraints": {},
+ "checkConstraints": {}
+ },
+ "world_growth_events": {
+ "name": "world_growth_events",
+ "columns": {
+ "id": {
+ "name": "id",
+ "type": "text",
+ "primaryKey": true,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "candidate_id": {
+ "name": "candidate_id",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "event_type": {
+ "name": "event_type",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "from_stage": {
+ "name": "from_stage",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": false,
+ "autoincrement": false
+ },
+ "to_stage": {
+ "name": "to_stage",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": false,
+ "autoincrement": false
+ },
+ "actor_type": {
+ "name": "actor_type",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": "'system'"
+ },
+ "weight_profile_id": {
+ "name": "weight_profile_id",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": false,
+ "autoincrement": false
+ },
+ "evidence_json": {
+ "name": "evidence_json",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": "'{}'"
+ },
+ "reason": {
+ "name": "reason",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": "''"
+ },
+ "created_at": {
+ "name": "created_at",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": "CURRENT_TIMESTAMP"
+ }
+ },
+ "indexes": {
+ "world_events_candidate_idx": {
+ "name": "world_events_candidate_idx",
+ "columns": [
+ "candidate_id"
+ ],
+ "isUnique": false
+ }
+ },
+ "foreignKeys": {
+ "world_growth_events_candidate_id_world_category_candidates_id_fk": {
+ "name": "world_growth_events_candidate_id_world_category_candidates_id_fk",
+ "tableFrom": "world_growth_events",
+ "tableTo": "world_category_candidates",
+ "columnsFrom": [
+ "candidate_id"
+ ],
+ "columnsTo": [
+ "id"
+ ],
+ "onDelete": "cascade",
+ "onUpdate": "no action"
+ },
+ "world_growth_events_weight_profile_id_world_weight_profiles_id_fk": {
+ "name": "world_growth_events_weight_profile_id_world_weight_profiles_id_fk",
+ "tableFrom": "world_growth_events",
+ "tableTo": "world_weight_profiles",
+ "columnsFrom": [
+ "weight_profile_id"
+ ],
+ "columnsTo": [
+ "id"
+ ],
+ "onDelete": "no action",
+ "onUpdate": "no action"
+ }
+ },
+ "compositePrimaryKeys": {},
+ "uniqueConstraints": {},
+ "checkConstraints": {}
+ },
+ "world_signal_assignments": {
+ "name": "world_signal_assignments",
+ "columns": {
+ "id": {
+ "name": "id",
+ "type": "text",
+ "primaryKey": true,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "vault_id": {
+ "name": "vault_id",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "debt_id": {
+ "name": "debt_id",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "candidate_id": {
+ "name": "candidate_id",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "confidence": {
+ "name": "confidence",
+ "type": "real",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "assignment_source": {
+ "name": "assignment_source",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": "'ai'"
+ },
+ "taxonomy_version": {
+ "name": "taxonomy_version",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": 1
+ },
+ "created_at": {
+ "name": "created_at",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": "CURRENT_TIMESTAMP"
+ },
+ "updated_at": {
+ "name": "updated_at",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": "CURRENT_TIMESTAMP"
+ }
+ },
+ "indexes": {
+ "world_signal_assignments_debt_id_unique": {
+ "name": "world_signal_assignments_debt_id_unique",
+ "columns": [
+ "debt_id"
+ ],
+ "isUnique": true
+ },
+ "world_signals_vault_idx": {
+ "name": "world_signals_vault_idx",
+ "columns": [
+ "vault_id"
+ ],
+ "isUnique": false
+ },
+ "world_signals_candidate_idx": {
+ "name": "world_signals_candidate_idx",
+ "columns": [
+ "candidate_id"
+ ],
+ "isUnique": false
+ }
+ },
+ "foreignKeys": {
+ "world_signal_assignments_vault_id_vaults_id_fk": {
+ "name": "world_signal_assignments_vault_id_vaults_id_fk",
+ "tableFrom": "world_signal_assignments",
+ "tableTo": "vaults",
+ "columnsFrom": [
+ "vault_id"
+ ],
+ "columnsTo": [
+ "id"
+ ],
+ "onDelete": "cascade",
+ "onUpdate": "no action"
+ },
+ "world_signal_assignments_debt_id_debts_id_fk": {
+ "name": "world_signal_assignments_debt_id_debts_id_fk",
+ "tableFrom": "world_signal_assignments",
+ "tableTo": "debts",
+ "columnsFrom": [
+ "debt_id"
+ ],
+ "columnsTo": [
+ "id"
+ ],
+ "onDelete": "cascade",
+ "onUpdate": "no action"
+ },
+ "world_signal_assignments_candidate_id_world_category_candidates_id_fk": {
+ "name": "world_signal_assignments_candidate_id_world_category_candidates_id_fk",
+ "tableFrom": "world_signal_assignments",
+ "tableTo": "world_category_candidates",
+ "columnsFrom": [
+ "candidate_id"
+ ],
+ "columnsTo": [
+ "id"
+ ],
+ "onDelete": "cascade",
+ "onUpdate": "no action"
+ }
+ },
+ "compositePrimaryKeys": {},
+ "uniqueConstraints": {},
+ "checkConstraints": {}
+ },
+ "world_weight_profiles": {
+ "name": "world_weight_profiles",
+ "columns": {
+ "id": {
+ "name": "id",
+ "type": "text",
+ "primaryKey": true,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "version": {
+ "name": "version",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "status": {
+ "name": "status",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": "'draft'"
+ },
+ "frequency_weight": {
+ "name": "frequency_weight",
+ "type": "real",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "growth_weight": {
+ "name": "growth_weight",
+ "type": "real",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "geography_weight": {
+ "name": "geography_weight",
+ "type": "real",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "recurrence_weight": {
+ "name": "recurrence_weight",
+ "type": "real",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "connection_weight": {
+ "name": "connection_weight",
+ "type": "real",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "quality_weight": {
+ "name": "quality_weight",
+ "type": "real",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "proposed_by": {
+ "name": "proposed_by",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": "'human'"
+ },
+ "model_ref": {
+ "name": "model_ref",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": false,
+ "autoincrement": false
+ },
+ "rationale": {
+ "name": "rationale",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": "''"
+ },
+ "created_at": {
+ "name": "created_at",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": "CURRENT_TIMESTAMP"
+ },
+ "activated_at": {
+ "name": "activated_at",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": false,
+ "autoincrement": false
+ }
+ },
+ "indexes": {
+ "world_weight_profiles_version_unique": {
+ "name": "world_weight_profiles_version_unique",
+ "columns": [
+ "version"
+ ],
+ "isUnique": true
+ }
+ },
+ "foreignKeys": {},
+ "compositePrimaryKeys": {},
+ "uniqueConstraints": {},
+ "checkConstraints": {}
+ }
+ },
+ "views": {},
+ "enums": {},
+ "_meta": {
+ "schemas": {},
+ "tables": {},
+ "columns": {}
+ },
+ "internal": {
+ "indexes": {}
+ }
+}
\ No newline at end of file
diff --git a/drizzle/meta/0006_snapshot.json b/drizzle/meta/0006_snapshot.json
new file mode 100644
index 0000000..53b102d
--- /dev/null
+++ b/drizzle/meta/0006_snapshot.json
@@ -0,0 +1,1412 @@
+{
+ "version": "6",
+ "dialect": "sqlite",
+ "id": "4e9c724b-0c6f-489f-a432-119c6e1c06c5",
+ "prevId": "b2cdbeb3-108a-42a0-8079-0e52cf97e01c",
+ "tables": {
+ "debts": {
+ "name": "debts",
+ "columns": {
+ "id": {
+ "name": "id",
+ "type": "text",
+ "primaryKey": true,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "vault_id": {
+ "name": "vault_id",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "kind": {
+ "name": "kind",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "custom_label": {
+ "name": "custom_label",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": false,
+ "autoincrement": false
+ },
+ "currency": {
+ "name": "currency",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "original": {
+ "name": "original",
+ "type": "real",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "balance": {
+ "name": "balance",
+ "type": "real",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "monthly": {
+ "name": "monthly",
+ "type": "real",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "due_day": {
+ "name": "due_day",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "method": {
+ "name": "method",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "sharing_mode": {
+ "name": "sharing_mode",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": "'private'"
+ },
+ "last_paid_at": {
+ "name": "last_paid_at",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": false,
+ "autoincrement": false
+ },
+ "payments": {
+ "name": "payments",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": 0
+ },
+ "created_at": {
+ "name": "created_at",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": "CURRENT_TIMESTAMP"
+ },
+ "updated_at": {
+ "name": "updated_at",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": "CURRENT_TIMESTAMP"
+ }
+ },
+ "indexes": {
+ "debts_vault_id_idx": {
+ "name": "debts_vault_id_idx",
+ "columns": [
+ "vault_id"
+ ],
+ "isUnique": false
+ }
+ },
+ "foreignKeys": {
+ "debts_vault_id_vaults_id_fk": {
+ "name": "debts_vault_id_vaults_id_fk",
+ "tableFrom": "debts",
+ "tableTo": "vaults",
+ "columnsFrom": [
+ "vault_id"
+ ],
+ "columnsTo": [
+ "id"
+ ],
+ "onDelete": "cascade",
+ "onUpdate": "no action"
+ }
+ },
+ "compositePrimaryKeys": {},
+ "uniqueConstraints": {},
+ "checkConstraints": {}
+ },
+ "lucky_income_claims": {
+ "name": "lucky_income_claims",
+ "columns": {
+ "id": {
+ "name": "id",
+ "type": "text",
+ "primaryKey": true,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "vault_id": {
+ "name": "vault_id",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "event_date": {
+ "name": "event_date",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "created_at": {
+ "name": "created_at",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": "CURRENT_TIMESTAMP"
+ }
+ },
+ "indexes": {
+ "lucky_income_vault_day_unique": {
+ "name": "lucky_income_vault_day_unique",
+ "columns": [
+ "vault_id",
+ "event_date"
+ ],
+ "isUnique": true
+ }
+ },
+ "foreignKeys": {
+ "lucky_income_claims_vault_id_vaults_id_fk": {
+ "name": "lucky_income_claims_vault_id_vaults_id_fk",
+ "tableFrom": "lucky_income_claims",
+ "tableTo": "vaults",
+ "columnsFrom": [
+ "vault_id"
+ ],
+ "columnsTo": [
+ "id"
+ ],
+ "onDelete": "cascade",
+ "onUpdate": "no action"
+ }
+ },
+ "compositePrimaryKeys": {},
+ "uniqueConstraints": {},
+ "checkConstraints": {}
+ },
+ "payment_records": {
+ "name": "payment_records",
+ "columns": {
+ "id": {
+ "name": "id",
+ "type": "text",
+ "primaryKey": true,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "vault_id": {
+ "name": "vault_id",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "debt_id": {
+ "name": "debt_id",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "scheduled_date": {
+ "name": "scheduled_date",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": false,
+ "autoincrement": false
+ },
+ "confirmed_at": {
+ "name": "confirmed_at",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "event_date": {
+ "name": "event_date",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": false,
+ "autoincrement": false
+ },
+ "cash_payment": {
+ "name": "cash_payment",
+ "type": "real",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "new_balance": {
+ "name": "new_balance",
+ "type": "real",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "source": {
+ "name": "source",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": "'self_report'"
+ },
+ "income_type": {
+ "name": "income_type",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": false,
+ "autoincrement": false
+ },
+ "created_at": {
+ "name": "created_at",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": "CURRENT_TIMESTAMP"
+ }
+ },
+ "indexes": {
+ "payments_vault_id_idx": {
+ "name": "payments_vault_id_idx",
+ "columns": [
+ "vault_id"
+ ],
+ "isUnique": false
+ },
+ "payments_debt_id_idx": {
+ "name": "payments_debt_id_idx",
+ "columns": [
+ "debt_id"
+ ],
+ "isUnique": false
+ }
+ },
+ "foreignKeys": {
+ "payment_records_vault_id_vaults_id_fk": {
+ "name": "payment_records_vault_id_vaults_id_fk",
+ "tableFrom": "payment_records",
+ "tableTo": "vaults",
+ "columnsFrom": [
+ "vault_id"
+ ],
+ "columnsTo": [
+ "id"
+ ],
+ "onDelete": "cascade",
+ "onUpdate": "no action"
+ },
+ "payment_records_debt_id_debts_id_fk": {
+ "name": "payment_records_debt_id_debts_id_fk",
+ "tableFrom": "payment_records",
+ "tableTo": "debts",
+ "columnsFrom": [
+ "debt_id"
+ ],
+ "columnsTo": [
+ "id"
+ ],
+ "onDelete": "cascade",
+ "onUpdate": "no action"
+ }
+ },
+ "compositePrimaryKeys": {},
+ "uniqueConstraints": {},
+ "checkConstraints": {}
+ },
+ "public_stories": {
+ "name": "public_stories",
+ "columns": {
+ "id": {
+ "name": "id",
+ "type": "text",
+ "primaryKey": true,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "vault_id": {
+ "name": "vault_id",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "debt_id": {
+ "name": "debt_id",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "anonymous_name": {
+ "name": "anonymous_name",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "country_code": {
+ "name": "country_code",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": "''"
+ },
+ "debt_kind": {
+ "name": "debt_kind",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "amount_band": {
+ "name": "amount_band",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "currency": {
+ "name": "currency",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "repayment_approach": {
+ "name": "repayment_approach",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": "'other'"
+ },
+ "story_text": {
+ "name": "story_text",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "status": {
+ "name": "status",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": "'pending'"
+ },
+ "created_at": {
+ "name": "created_at",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": "CURRENT_TIMESTAMP"
+ },
+ "updated_at": {
+ "name": "updated_at",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": "CURRENT_TIMESTAMP"
+ }
+ },
+ "indexes": {
+ "public_stories_status_idx": {
+ "name": "public_stories_status_idx",
+ "columns": [
+ "status"
+ ],
+ "isUnique": false
+ },
+ "public_stories_vault_idx": {
+ "name": "public_stories_vault_idx",
+ "columns": [
+ "vault_id"
+ ],
+ "isUnique": false
+ }
+ },
+ "foreignKeys": {
+ "public_stories_vault_id_vaults_id_fk": {
+ "name": "public_stories_vault_id_vaults_id_fk",
+ "tableFrom": "public_stories",
+ "tableTo": "vaults",
+ "columnsFrom": [
+ "vault_id"
+ ],
+ "columnsTo": [
+ "id"
+ ],
+ "onDelete": "cascade",
+ "onUpdate": "no action"
+ },
+ "public_stories_debt_id_debts_id_fk": {
+ "name": "public_stories_debt_id_debts_id_fk",
+ "tableFrom": "public_stories",
+ "tableTo": "debts",
+ "columnsFrom": [
+ "debt_id"
+ ],
+ "columnsTo": [
+ "id"
+ ],
+ "onDelete": "cascade",
+ "onUpdate": "no action"
+ }
+ },
+ "compositePrimaryKeys": {},
+ "uniqueConstraints": {},
+ "checkConstraints": {}
+ },
+ "story_encouragements": {
+ "name": "story_encouragements",
+ "columns": {
+ "id": {
+ "name": "id",
+ "type": "text",
+ "primaryKey": true,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "story_id": {
+ "name": "story_id",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "vault_id": {
+ "name": "vault_id",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "created_at": {
+ "name": "created_at",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": "CURRENT_TIMESTAMP"
+ }
+ },
+ "indexes": {
+ "story_encouragement_unique": {
+ "name": "story_encouragement_unique",
+ "columns": [
+ "story_id",
+ "vault_id"
+ ],
+ "isUnique": true
+ },
+ "story_encouragement_story_idx": {
+ "name": "story_encouragement_story_idx",
+ "columns": [
+ "story_id"
+ ],
+ "isUnique": false
+ }
+ },
+ "foreignKeys": {
+ "story_encouragements_story_id_public_stories_id_fk": {
+ "name": "story_encouragements_story_id_public_stories_id_fk",
+ "tableFrom": "story_encouragements",
+ "tableTo": "public_stories",
+ "columnsFrom": [
+ "story_id"
+ ],
+ "columnsTo": [
+ "id"
+ ],
+ "onDelete": "cascade",
+ "onUpdate": "no action"
+ },
+ "story_encouragements_vault_id_vaults_id_fk": {
+ "name": "story_encouragements_vault_id_vaults_id_fk",
+ "tableFrom": "story_encouragements",
+ "tableTo": "vaults",
+ "columnsFrom": [
+ "vault_id"
+ ],
+ "columnsTo": [
+ "id"
+ ],
+ "onDelete": "cascade",
+ "onUpdate": "no action"
+ }
+ },
+ "compositePrimaryKeys": {},
+ "uniqueConstraints": {},
+ "checkConstraints": {}
+ },
+ "story_reports": {
+ "name": "story_reports",
+ "columns": {
+ "id": {
+ "name": "id",
+ "type": "text",
+ "primaryKey": true,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "story_id": {
+ "name": "story_id",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "reporter_vault_id": {
+ "name": "reporter_vault_id",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "reason": {
+ "name": "reason",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "details": {
+ "name": "details",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": "''"
+ },
+ "status": {
+ "name": "status",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": "'open'"
+ },
+ "created_at": {
+ "name": "created_at",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": "CURRENT_TIMESTAMP"
+ },
+ "resolved_at": {
+ "name": "resolved_at",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": false,
+ "autoincrement": false
+ }
+ },
+ "indexes": {
+ "story_report_unique": {
+ "name": "story_report_unique",
+ "columns": [
+ "story_id",
+ "reporter_vault_id"
+ ],
+ "isUnique": true
+ },
+ "story_reports_status_idx": {
+ "name": "story_reports_status_idx",
+ "columns": [
+ "status"
+ ],
+ "isUnique": false
+ }
+ },
+ "foreignKeys": {
+ "story_reports_story_id_public_stories_id_fk": {
+ "name": "story_reports_story_id_public_stories_id_fk",
+ "tableFrom": "story_reports",
+ "tableTo": "public_stories",
+ "columnsFrom": [
+ "story_id"
+ ],
+ "columnsTo": [
+ "id"
+ ],
+ "onDelete": "cascade",
+ "onUpdate": "no action"
+ },
+ "story_reports_reporter_vault_id_vaults_id_fk": {
+ "name": "story_reports_reporter_vault_id_vaults_id_fk",
+ "tableFrom": "story_reports",
+ "tableTo": "vaults",
+ "columnsFrom": [
+ "reporter_vault_id"
+ ],
+ "columnsTo": [
+ "id"
+ ],
+ "onDelete": "cascade",
+ "onUpdate": "no action"
+ }
+ },
+ "compositePrimaryKeys": {},
+ "uniqueConstraints": {},
+ "checkConstraints": {}
+ },
+ "vaults": {
+ "name": "vaults",
+ "columns": {
+ "id": {
+ "name": "id",
+ "type": "text",
+ "primaryKey": true,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "recovery_hash": {
+ "name": "recovery_hash",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "alias": {
+ "name": "alias",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "region": {
+ "name": "region",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "pressure": {
+ "name": "pressure",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": "''"
+ },
+ "position_x": {
+ "name": "position_x",
+ "type": "real",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": 47
+ },
+ "position_y": {
+ "name": "position_y",
+ "type": "real",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": 63
+ },
+ "locale": {
+ "name": "locale",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": "'zh'"
+ },
+ "country_code": {
+ "name": "country_code",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": "''"
+ },
+ "country_name": {
+ "name": "country_name",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": "''"
+ },
+ "display_currency": {
+ "name": "display_currency",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": "'CNY'"
+ },
+ "monthly_income": {
+ "name": "monthly_income",
+ "type": "real",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": 0
+ },
+ "monthly_expenses": {
+ "name": "monthly_expenses",
+ "type": "real",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": 0
+ },
+ "discovery_consent": {
+ "name": "discovery_consent",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": false
+ },
+ "created_at": {
+ "name": "created_at",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": "CURRENT_TIMESTAMP"
+ },
+ "updated_at": {
+ "name": "updated_at",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": "CURRENT_TIMESTAMP"
+ }
+ },
+ "indexes": {
+ "vaults_recovery_hash_unique": {
+ "name": "vaults_recovery_hash_unique",
+ "columns": [
+ "recovery_hash"
+ ],
+ "isUnique": true
+ }
+ },
+ "foreignKeys": {},
+ "compositePrimaryKeys": {},
+ "uniqueConstraints": {},
+ "checkConstraints": {}
+ },
+ "world_category_candidates": {
+ "name": "world_category_candidates",
+ "columns": {
+ "id": {
+ "name": "id",
+ "type": "text",
+ "primaryKey": true,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "canonical_key": {
+ "name": "canonical_key",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "parent_kind": {
+ "name": "parent_kind",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": "'other'"
+ },
+ "name_zh": {
+ "name": "name_zh",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "name_en": {
+ "name": "name_en",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "description_zh": {
+ "name": "description_zh",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": "''"
+ },
+ "description_en": {
+ "name": "description_en",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": "''"
+ },
+ "status": {
+ "name": "status",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": "'candidate'"
+ },
+ "stage": {
+ "name": "stage",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": 0
+ },
+ "confidence": {
+ "name": "confidence",
+ "type": "real",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": 0
+ },
+ "unique_vaults": {
+ "name": "unique_vaults",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": 0
+ },
+ "region_count": {
+ "name": "region_count",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": 0
+ },
+ "mention_count": {
+ "name": "mention_count",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": 0
+ },
+ "emergence_score": {
+ "name": "emergence_score",
+ "type": "real",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": 0
+ },
+ "weight_profile_id": {
+ "name": "weight_profile_id",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": false,
+ "autoincrement": false
+ },
+ "merged_into_id": {
+ "name": "merged_into_id",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": false,
+ "autoincrement": false
+ },
+ "proposed_at": {
+ "name": "proposed_at",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": "CURRENT_TIMESTAMP"
+ },
+ "reviewed_at": {
+ "name": "reviewed_at",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": false,
+ "autoincrement": false
+ },
+ "published_at": {
+ "name": "published_at",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": false,
+ "autoincrement": false
+ },
+ "updated_at": {
+ "name": "updated_at",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": "CURRENT_TIMESTAMP"
+ }
+ },
+ "indexes": {
+ "world_category_candidates_canonical_key_unique": {
+ "name": "world_category_candidates_canonical_key_unique",
+ "columns": [
+ "canonical_key"
+ ],
+ "isUnique": true
+ },
+ "world_candidates_status_idx": {
+ "name": "world_candidates_status_idx",
+ "columns": [
+ "status"
+ ],
+ "isUnique": false
+ },
+ "world_candidates_score_idx": {
+ "name": "world_candidates_score_idx",
+ "columns": [
+ "emergence_score"
+ ],
+ "isUnique": false
+ }
+ },
+ "foreignKeys": {
+ "world_category_candidates_weight_profile_id_world_weight_profiles_id_fk": {
+ "name": "world_category_candidates_weight_profile_id_world_weight_profiles_id_fk",
+ "tableFrom": "world_category_candidates",
+ "tableTo": "world_weight_profiles",
+ "columnsFrom": [
+ "weight_profile_id"
+ ],
+ "columnsTo": [
+ "id"
+ ],
+ "onDelete": "no action",
+ "onUpdate": "no action"
+ }
+ },
+ "compositePrimaryKeys": {},
+ "uniqueConstraints": {},
+ "checkConstraints": {}
+ },
+ "world_growth_events": {
+ "name": "world_growth_events",
+ "columns": {
+ "id": {
+ "name": "id",
+ "type": "text",
+ "primaryKey": true,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "candidate_id": {
+ "name": "candidate_id",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "event_type": {
+ "name": "event_type",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "from_stage": {
+ "name": "from_stage",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": false,
+ "autoincrement": false
+ },
+ "to_stage": {
+ "name": "to_stage",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": false,
+ "autoincrement": false
+ },
+ "actor_type": {
+ "name": "actor_type",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": "'system'"
+ },
+ "weight_profile_id": {
+ "name": "weight_profile_id",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": false,
+ "autoincrement": false
+ },
+ "evidence_json": {
+ "name": "evidence_json",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": "'{}'"
+ },
+ "reason": {
+ "name": "reason",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": "''"
+ },
+ "created_at": {
+ "name": "created_at",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": "CURRENT_TIMESTAMP"
+ }
+ },
+ "indexes": {
+ "world_events_candidate_idx": {
+ "name": "world_events_candidate_idx",
+ "columns": [
+ "candidate_id"
+ ],
+ "isUnique": false
+ }
+ },
+ "foreignKeys": {
+ "world_growth_events_candidate_id_world_category_candidates_id_fk": {
+ "name": "world_growth_events_candidate_id_world_category_candidates_id_fk",
+ "tableFrom": "world_growth_events",
+ "tableTo": "world_category_candidates",
+ "columnsFrom": [
+ "candidate_id"
+ ],
+ "columnsTo": [
+ "id"
+ ],
+ "onDelete": "cascade",
+ "onUpdate": "no action"
+ },
+ "world_growth_events_weight_profile_id_world_weight_profiles_id_fk": {
+ "name": "world_growth_events_weight_profile_id_world_weight_profiles_id_fk",
+ "tableFrom": "world_growth_events",
+ "tableTo": "world_weight_profiles",
+ "columnsFrom": [
+ "weight_profile_id"
+ ],
+ "columnsTo": [
+ "id"
+ ],
+ "onDelete": "no action",
+ "onUpdate": "no action"
+ }
+ },
+ "compositePrimaryKeys": {},
+ "uniqueConstraints": {},
+ "checkConstraints": {}
+ },
+ "world_signal_assignments": {
+ "name": "world_signal_assignments",
+ "columns": {
+ "id": {
+ "name": "id",
+ "type": "text",
+ "primaryKey": true,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "vault_id": {
+ "name": "vault_id",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "debt_id": {
+ "name": "debt_id",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "candidate_id": {
+ "name": "candidate_id",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "confidence": {
+ "name": "confidence",
+ "type": "real",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "assignment_source": {
+ "name": "assignment_source",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": "'ai'"
+ },
+ "taxonomy_version": {
+ "name": "taxonomy_version",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": 1
+ },
+ "created_at": {
+ "name": "created_at",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": "CURRENT_TIMESTAMP"
+ },
+ "updated_at": {
+ "name": "updated_at",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": "CURRENT_TIMESTAMP"
+ }
+ },
+ "indexes": {
+ "world_signal_assignments_debt_id_unique": {
+ "name": "world_signal_assignments_debt_id_unique",
+ "columns": [
+ "debt_id"
+ ],
+ "isUnique": true
+ },
+ "world_signals_vault_idx": {
+ "name": "world_signals_vault_idx",
+ "columns": [
+ "vault_id"
+ ],
+ "isUnique": false
+ },
+ "world_signals_candidate_idx": {
+ "name": "world_signals_candidate_idx",
+ "columns": [
+ "candidate_id"
+ ],
+ "isUnique": false
+ }
+ },
+ "foreignKeys": {
+ "world_signal_assignments_vault_id_vaults_id_fk": {
+ "name": "world_signal_assignments_vault_id_vaults_id_fk",
+ "tableFrom": "world_signal_assignments",
+ "tableTo": "vaults",
+ "columnsFrom": [
+ "vault_id"
+ ],
+ "columnsTo": [
+ "id"
+ ],
+ "onDelete": "cascade",
+ "onUpdate": "no action"
+ },
+ "world_signal_assignments_debt_id_debts_id_fk": {
+ "name": "world_signal_assignments_debt_id_debts_id_fk",
+ "tableFrom": "world_signal_assignments",
+ "tableTo": "debts",
+ "columnsFrom": [
+ "debt_id"
+ ],
+ "columnsTo": [
+ "id"
+ ],
+ "onDelete": "cascade",
+ "onUpdate": "no action"
+ },
+ "world_signal_assignments_candidate_id_world_category_candidates_id_fk": {
+ "name": "world_signal_assignments_candidate_id_world_category_candidates_id_fk",
+ "tableFrom": "world_signal_assignments",
+ "tableTo": "world_category_candidates",
+ "columnsFrom": [
+ "candidate_id"
+ ],
+ "columnsTo": [
+ "id"
+ ],
+ "onDelete": "cascade",
+ "onUpdate": "no action"
+ }
+ },
+ "compositePrimaryKeys": {},
+ "uniqueConstraints": {},
+ "checkConstraints": {}
+ },
+ "world_weight_profiles": {
+ "name": "world_weight_profiles",
+ "columns": {
+ "id": {
+ "name": "id",
+ "type": "text",
+ "primaryKey": true,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "version": {
+ "name": "version",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "status": {
+ "name": "status",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": "'draft'"
+ },
+ "frequency_weight": {
+ "name": "frequency_weight",
+ "type": "real",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "growth_weight": {
+ "name": "growth_weight",
+ "type": "real",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "geography_weight": {
+ "name": "geography_weight",
+ "type": "real",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "recurrence_weight": {
+ "name": "recurrence_weight",
+ "type": "real",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "connection_weight": {
+ "name": "connection_weight",
+ "type": "real",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "quality_weight": {
+ "name": "quality_weight",
+ "type": "real",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "proposed_by": {
+ "name": "proposed_by",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": "'human'"
+ },
+ "model_ref": {
+ "name": "model_ref",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": false,
+ "autoincrement": false
+ },
+ "rationale": {
+ "name": "rationale",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": "''"
+ },
+ "created_at": {
+ "name": "created_at",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": "CURRENT_TIMESTAMP"
+ },
+ "activated_at": {
+ "name": "activated_at",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": false,
+ "autoincrement": false
+ }
+ },
+ "indexes": {
+ "world_weight_profiles_version_unique": {
+ "name": "world_weight_profiles_version_unique",
+ "columns": [
+ "version"
+ ],
+ "isUnique": true
+ }
+ },
+ "foreignKeys": {},
+ "compositePrimaryKeys": {},
+ "uniqueConstraints": {},
+ "checkConstraints": {}
+ }
+ },
+ "views": {},
+ "enums": {},
+ "_meta": {
+ "schemas": {},
+ "tables": {},
+ "columns": {}
+ },
+ "internal": {
+ "indexes": {}
+ }
+}
\ No newline at end of file
diff --git a/drizzle/meta/0007_snapshot.json b/drizzle/meta/0007_snapshot.json
new file mode 100644
index 0000000..57fb025
--- /dev/null
+++ b/drizzle/meta/0007_snapshot.json
@@ -0,0 +1,1594 @@
+{
+ "version": "6",
+ "dialect": "sqlite",
+ "id": "462d69f3-3a66-4d4b-b26b-33eb4311a4cf",
+ "prevId": "4e9c724b-0c6f-489f-a432-119c6e1c06c5",
+ "tables": {
+ "community_moderation_actions": {
+ "name": "community_moderation_actions",
+ "columns": {
+ "id": {
+ "name": "id",
+ "type": "text",
+ "primaryKey": true,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "story_id": {
+ "name": "story_id",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "actor_digest": {
+ "name": "actor_digest",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "action": {
+ "name": "action",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "from_status": {
+ "name": "from_status",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "to_status": {
+ "name": "to_status",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "note": {
+ "name": "note",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": "''"
+ },
+ "created_at": {
+ "name": "created_at",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": "CURRENT_TIMESTAMP"
+ }
+ },
+ "indexes": {
+ "community_moderation_story_idx": {
+ "name": "community_moderation_story_idx",
+ "columns": [
+ "story_id"
+ ],
+ "isUnique": false
+ },
+ "community_moderation_created_idx": {
+ "name": "community_moderation_created_idx",
+ "columns": [
+ "created_at"
+ ],
+ "isUnique": false
+ }
+ },
+ "foreignKeys": {
+ "community_moderation_actions_story_id_public_stories_id_fk": {
+ "name": "community_moderation_actions_story_id_public_stories_id_fk",
+ "tableFrom": "community_moderation_actions",
+ "tableTo": "public_stories",
+ "columnsFrom": [
+ "story_id"
+ ],
+ "columnsTo": [
+ "id"
+ ],
+ "onDelete": "cascade",
+ "onUpdate": "no action"
+ }
+ },
+ "compositePrimaryKeys": {},
+ "uniqueConstraints": {},
+ "checkConstraints": {}
+ },
+ "community_rate_limits": {
+ "name": "community_rate_limits",
+ "columns": {
+ "id": {
+ "name": "id",
+ "type": "text",
+ "primaryKey": true,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "vault_id": {
+ "name": "vault_id",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "action": {
+ "name": "action",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "window_key": {
+ "name": "window_key",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "count": {
+ "name": "count",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": 0
+ },
+ "updated_at": {
+ "name": "updated_at",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": "CURRENT_TIMESTAMP"
+ }
+ },
+ "indexes": {
+ "community_rate_vault_action_window_unique": {
+ "name": "community_rate_vault_action_window_unique",
+ "columns": [
+ "vault_id",
+ "action",
+ "window_key"
+ ],
+ "isUnique": true
+ },
+ "community_rate_window_idx": {
+ "name": "community_rate_window_idx",
+ "columns": [
+ "window_key"
+ ],
+ "isUnique": false
+ }
+ },
+ "foreignKeys": {
+ "community_rate_limits_vault_id_vaults_id_fk": {
+ "name": "community_rate_limits_vault_id_vaults_id_fk",
+ "tableFrom": "community_rate_limits",
+ "tableTo": "vaults",
+ "columnsFrom": [
+ "vault_id"
+ ],
+ "columnsTo": [
+ "id"
+ ],
+ "onDelete": "cascade",
+ "onUpdate": "no action"
+ }
+ },
+ "compositePrimaryKeys": {},
+ "uniqueConstraints": {},
+ "checkConstraints": {}
+ },
+ "debts": {
+ "name": "debts",
+ "columns": {
+ "id": {
+ "name": "id",
+ "type": "text",
+ "primaryKey": true,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "vault_id": {
+ "name": "vault_id",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "kind": {
+ "name": "kind",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "custom_label": {
+ "name": "custom_label",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": false,
+ "autoincrement": false
+ },
+ "currency": {
+ "name": "currency",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "original": {
+ "name": "original",
+ "type": "real",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "balance": {
+ "name": "balance",
+ "type": "real",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "monthly": {
+ "name": "monthly",
+ "type": "real",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "due_day": {
+ "name": "due_day",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "method": {
+ "name": "method",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "sharing_mode": {
+ "name": "sharing_mode",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": "'private'"
+ },
+ "last_paid_at": {
+ "name": "last_paid_at",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": false,
+ "autoincrement": false
+ },
+ "payments": {
+ "name": "payments",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": 0
+ },
+ "created_at": {
+ "name": "created_at",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": "CURRENT_TIMESTAMP"
+ },
+ "updated_at": {
+ "name": "updated_at",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": "CURRENT_TIMESTAMP"
+ }
+ },
+ "indexes": {
+ "debts_vault_id_idx": {
+ "name": "debts_vault_id_idx",
+ "columns": [
+ "vault_id"
+ ],
+ "isUnique": false
+ }
+ },
+ "foreignKeys": {
+ "debts_vault_id_vaults_id_fk": {
+ "name": "debts_vault_id_vaults_id_fk",
+ "tableFrom": "debts",
+ "tableTo": "vaults",
+ "columnsFrom": [
+ "vault_id"
+ ],
+ "columnsTo": [
+ "id"
+ ],
+ "onDelete": "cascade",
+ "onUpdate": "no action"
+ }
+ },
+ "compositePrimaryKeys": {},
+ "uniqueConstraints": {},
+ "checkConstraints": {}
+ },
+ "lucky_income_claims": {
+ "name": "lucky_income_claims",
+ "columns": {
+ "id": {
+ "name": "id",
+ "type": "text",
+ "primaryKey": true,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "vault_id": {
+ "name": "vault_id",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "event_date": {
+ "name": "event_date",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "created_at": {
+ "name": "created_at",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": "CURRENT_TIMESTAMP"
+ }
+ },
+ "indexes": {
+ "lucky_income_vault_day_unique": {
+ "name": "lucky_income_vault_day_unique",
+ "columns": [
+ "vault_id",
+ "event_date"
+ ],
+ "isUnique": true
+ }
+ },
+ "foreignKeys": {
+ "lucky_income_claims_vault_id_vaults_id_fk": {
+ "name": "lucky_income_claims_vault_id_vaults_id_fk",
+ "tableFrom": "lucky_income_claims",
+ "tableTo": "vaults",
+ "columnsFrom": [
+ "vault_id"
+ ],
+ "columnsTo": [
+ "id"
+ ],
+ "onDelete": "cascade",
+ "onUpdate": "no action"
+ }
+ },
+ "compositePrimaryKeys": {},
+ "uniqueConstraints": {},
+ "checkConstraints": {}
+ },
+ "payment_records": {
+ "name": "payment_records",
+ "columns": {
+ "id": {
+ "name": "id",
+ "type": "text",
+ "primaryKey": true,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "vault_id": {
+ "name": "vault_id",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "debt_id": {
+ "name": "debt_id",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "scheduled_date": {
+ "name": "scheduled_date",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": false,
+ "autoincrement": false
+ },
+ "confirmed_at": {
+ "name": "confirmed_at",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "event_date": {
+ "name": "event_date",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": false,
+ "autoincrement": false
+ },
+ "cash_payment": {
+ "name": "cash_payment",
+ "type": "real",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "new_balance": {
+ "name": "new_balance",
+ "type": "real",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "source": {
+ "name": "source",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": "'self_report'"
+ },
+ "income_type": {
+ "name": "income_type",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": false,
+ "autoincrement": false
+ },
+ "created_at": {
+ "name": "created_at",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": "CURRENT_TIMESTAMP"
+ }
+ },
+ "indexes": {
+ "payments_vault_id_idx": {
+ "name": "payments_vault_id_idx",
+ "columns": [
+ "vault_id"
+ ],
+ "isUnique": false
+ },
+ "payments_debt_id_idx": {
+ "name": "payments_debt_id_idx",
+ "columns": [
+ "debt_id"
+ ],
+ "isUnique": false
+ }
+ },
+ "foreignKeys": {
+ "payment_records_vault_id_vaults_id_fk": {
+ "name": "payment_records_vault_id_vaults_id_fk",
+ "tableFrom": "payment_records",
+ "tableTo": "vaults",
+ "columnsFrom": [
+ "vault_id"
+ ],
+ "columnsTo": [
+ "id"
+ ],
+ "onDelete": "cascade",
+ "onUpdate": "no action"
+ },
+ "payment_records_debt_id_debts_id_fk": {
+ "name": "payment_records_debt_id_debts_id_fk",
+ "tableFrom": "payment_records",
+ "tableTo": "debts",
+ "columnsFrom": [
+ "debt_id"
+ ],
+ "columnsTo": [
+ "id"
+ ],
+ "onDelete": "cascade",
+ "onUpdate": "no action"
+ }
+ },
+ "compositePrimaryKeys": {},
+ "uniqueConstraints": {},
+ "checkConstraints": {}
+ },
+ "public_stories": {
+ "name": "public_stories",
+ "columns": {
+ "id": {
+ "name": "id",
+ "type": "text",
+ "primaryKey": true,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "vault_id": {
+ "name": "vault_id",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "debt_id": {
+ "name": "debt_id",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "anonymous_name": {
+ "name": "anonymous_name",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "country_code": {
+ "name": "country_code",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": "''"
+ },
+ "debt_kind": {
+ "name": "debt_kind",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "amount_band": {
+ "name": "amount_band",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "currency": {
+ "name": "currency",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "repayment_approach": {
+ "name": "repayment_approach",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": "'other'"
+ },
+ "story_text": {
+ "name": "story_text",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "status": {
+ "name": "status",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": "'pending'"
+ },
+ "created_at": {
+ "name": "created_at",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": "CURRENT_TIMESTAMP"
+ },
+ "updated_at": {
+ "name": "updated_at",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": "CURRENT_TIMESTAMP"
+ }
+ },
+ "indexes": {
+ "public_stories_status_idx": {
+ "name": "public_stories_status_idx",
+ "columns": [
+ "status"
+ ],
+ "isUnique": false
+ },
+ "public_stories_vault_idx": {
+ "name": "public_stories_vault_idx",
+ "columns": [
+ "vault_id"
+ ],
+ "isUnique": false
+ }
+ },
+ "foreignKeys": {
+ "public_stories_vault_id_vaults_id_fk": {
+ "name": "public_stories_vault_id_vaults_id_fk",
+ "tableFrom": "public_stories",
+ "tableTo": "vaults",
+ "columnsFrom": [
+ "vault_id"
+ ],
+ "columnsTo": [
+ "id"
+ ],
+ "onDelete": "cascade",
+ "onUpdate": "no action"
+ },
+ "public_stories_debt_id_debts_id_fk": {
+ "name": "public_stories_debt_id_debts_id_fk",
+ "tableFrom": "public_stories",
+ "tableTo": "debts",
+ "columnsFrom": [
+ "debt_id"
+ ],
+ "columnsTo": [
+ "id"
+ ],
+ "onDelete": "cascade",
+ "onUpdate": "no action"
+ }
+ },
+ "compositePrimaryKeys": {},
+ "uniqueConstraints": {},
+ "checkConstraints": {}
+ },
+ "story_encouragements": {
+ "name": "story_encouragements",
+ "columns": {
+ "id": {
+ "name": "id",
+ "type": "text",
+ "primaryKey": true,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "story_id": {
+ "name": "story_id",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "vault_id": {
+ "name": "vault_id",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "created_at": {
+ "name": "created_at",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": "CURRENT_TIMESTAMP"
+ }
+ },
+ "indexes": {
+ "story_encouragement_unique": {
+ "name": "story_encouragement_unique",
+ "columns": [
+ "story_id",
+ "vault_id"
+ ],
+ "isUnique": true
+ },
+ "story_encouragement_story_idx": {
+ "name": "story_encouragement_story_idx",
+ "columns": [
+ "story_id"
+ ],
+ "isUnique": false
+ }
+ },
+ "foreignKeys": {
+ "story_encouragements_story_id_public_stories_id_fk": {
+ "name": "story_encouragements_story_id_public_stories_id_fk",
+ "tableFrom": "story_encouragements",
+ "tableTo": "public_stories",
+ "columnsFrom": [
+ "story_id"
+ ],
+ "columnsTo": [
+ "id"
+ ],
+ "onDelete": "cascade",
+ "onUpdate": "no action"
+ },
+ "story_encouragements_vault_id_vaults_id_fk": {
+ "name": "story_encouragements_vault_id_vaults_id_fk",
+ "tableFrom": "story_encouragements",
+ "tableTo": "vaults",
+ "columnsFrom": [
+ "vault_id"
+ ],
+ "columnsTo": [
+ "id"
+ ],
+ "onDelete": "cascade",
+ "onUpdate": "no action"
+ }
+ },
+ "compositePrimaryKeys": {},
+ "uniqueConstraints": {},
+ "checkConstraints": {}
+ },
+ "story_reports": {
+ "name": "story_reports",
+ "columns": {
+ "id": {
+ "name": "id",
+ "type": "text",
+ "primaryKey": true,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "story_id": {
+ "name": "story_id",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "reporter_vault_id": {
+ "name": "reporter_vault_id",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "reason": {
+ "name": "reason",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "details": {
+ "name": "details",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": "''"
+ },
+ "status": {
+ "name": "status",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": "'open'"
+ },
+ "created_at": {
+ "name": "created_at",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": "CURRENT_TIMESTAMP"
+ },
+ "resolved_at": {
+ "name": "resolved_at",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": false,
+ "autoincrement": false
+ }
+ },
+ "indexes": {
+ "story_report_unique": {
+ "name": "story_report_unique",
+ "columns": [
+ "story_id",
+ "reporter_vault_id"
+ ],
+ "isUnique": true
+ },
+ "story_reports_status_idx": {
+ "name": "story_reports_status_idx",
+ "columns": [
+ "status"
+ ],
+ "isUnique": false
+ }
+ },
+ "foreignKeys": {
+ "story_reports_story_id_public_stories_id_fk": {
+ "name": "story_reports_story_id_public_stories_id_fk",
+ "tableFrom": "story_reports",
+ "tableTo": "public_stories",
+ "columnsFrom": [
+ "story_id"
+ ],
+ "columnsTo": [
+ "id"
+ ],
+ "onDelete": "cascade",
+ "onUpdate": "no action"
+ },
+ "story_reports_reporter_vault_id_vaults_id_fk": {
+ "name": "story_reports_reporter_vault_id_vaults_id_fk",
+ "tableFrom": "story_reports",
+ "tableTo": "vaults",
+ "columnsFrom": [
+ "reporter_vault_id"
+ ],
+ "columnsTo": [
+ "id"
+ ],
+ "onDelete": "cascade",
+ "onUpdate": "no action"
+ }
+ },
+ "compositePrimaryKeys": {},
+ "uniqueConstraints": {},
+ "checkConstraints": {}
+ },
+ "vaults": {
+ "name": "vaults",
+ "columns": {
+ "id": {
+ "name": "id",
+ "type": "text",
+ "primaryKey": true,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "recovery_hash": {
+ "name": "recovery_hash",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "alias": {
+ "name": "alias",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "region": {
+ "name": "region",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "pressure": {
+ "name": "pressure",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": "''"
+ },
+ "position_x": {
+ "name": "position_x",
+ "type": "real",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": 47
+ },
+ "position_y": {
+ "name": "position_y",
+ "type": "real",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": 63
+ },
+ "locale": {
+ "name": "locale",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": "'zh'"
+ },
+ "country_code": {
+ "name": "country_code",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": "''"
+ },
+ "country_name": {
+ "name": "country_name",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": "''"
+ },
+ "display_currency": {
+ "name": "display_currency",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": "'CNY'"
+ },
+ "monthly_income": {
+ "name": "monthly_income",
+ "type": "real",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": 0
+ },
+ "monthly_expenses": {
+ "name": "monthly_expenses",
+ "type": "real",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": 0
+ },
+ "discovery_consent": {
+ "name": "discovery_consent",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": false
+ },
+ "created_at": {
+ "name": "created_at",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": "CURRENT_TIMESTAMP"
+ },
+ "updated_at": {
+ "name": "updated_at",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": "CURRENT_TIMESTAMP"
+ }
+ },
+ "indexes": {
+ "vaults_recovery_hash_unique": {
+ "name": "vaults_recovery_hash_unique",
+ "columns": [
+ "recovery_hash"
+ ],
+ "isUnique": true
+ }
+ },
+ "foreignKeys": {},
+ "compositePrimaryKeys": {},
+ "uniqueConstraints": {},
+ "checkConstraints": {}
+ },
+ "world_category_candidates": {
+ "name": "world_category_candidates",
+ "columns": {
+ "id": {
+ "name": "id",
+ "type": "text",
+ "primaryKey": true,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "canonical_key": {
+ "name": "canonical_key",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "parent_kind": {
+ "name": "parent_kind",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": "'other'"
+ },
+ "name_zh": {
+ "name": "name_zh",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "name_en": {
+ "name": "name_en",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "description_zh": {
+ "name": "description_zh",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": "''"
+ },
+ "description_en": {
+ "name": "description_en",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": "''"
+ },
+ "status": {
+ "name": "status",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": "'candidate'"
+ },
+ "stage": {
+ "name": "stage",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": 0
+ },
+ "confidence": {
+ "name": "confidence",
+ "type": "real",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": 0
+ },
+ "unique_vaults": {
+ "name": "unique_vaults",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": 0
+ },
+ "region_count": {
+ "name": "region_count",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": 0
+ },
+ "mention_count": {
+ "name": "mention_count",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": 0
+ },
+ "emergence_score": {
+ "name": "emergence_score",
+ "type": "real",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": 0
+ },
+ "weight_profile_id": {
+ "name": "weight_profile_id",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": false,
+ "autoincrement": false
+ },
+ "merged_into_id": {
+ "name": "merged_into_id",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": false,
+ "autoincrement": false
+ },
+ "proposed_at": {
+ "name": "proposed_at",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": "CURRENT_TIMESTAMP"
+ },
+ "reviewed_at": {
+ "name": "reviewed_at",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": false,
+ "autoincrement": false
+ },
+ "published_at": {
+ "name": "published_at",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": false,
+ "autoincrement": false
+ },
+ "updated_at": {
+ "name": "updated_at",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": "CURRENT_TIMESTAMP"
+ }
+ },
+ "indexes": {
+ "world_category_candidates_canonical_key_unique": {
+ "name": "world_category_candidates_canonical_key_unique",
+ "columns": [
+ "canonical_key"
+ ],
+ "isUnique": true
+ },
+ "world_candidates_status_idx": {
+ "name": "world_candidates_status_idx",
+ "columns": [
+ "status"
+ ],
+ "isUnique": false
+ },
+ "world_candidates_score_idx": {
+ "name": "world_candidates_score_idx",
+ "columns": [
+ "emergence_score"
+ ],
+ "isUnique": false
+ }
+ },
+ "foreignKeys": {
+ "world_category_candidates_weight_profile_id_world_weight_profiles_id_fk": {
+ "name": "world_category_candidates_weight_profile_id_world_weight_profiles_id_fk",
+ "tableFrom": "world_category_candidates",
+ "tableTo": "world_weight_profiles",
+ "columnsFrom": [
+ "weight_profile_id"
+ ],
+ "columnsTo": [
+ "id"
+ ],
+ "onDelete": "no action",
+ "onUpdate": "no action"
+ }
+ },
+ "compositePrimaryKeys": {},
+ "uniqueConstraints": {},
+ "checkConstraints": {}
+ },
+ "world_growth_events": {
+ "name": "world_growth_events",
+ "columns": {
+ "id": {
+ "name": "id",
+ "type": "text",
+ "primaryKey": true,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "candidate_id": {
+ "name": "candidate_id",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "event_type": {
+ "name": "event_type",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "from_stage": {
+ "name": "from_stage",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": false,
+ "autoincrement": false
+ },
+ "to_stage": {
+ "name": "to_stage",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": false,
+ "autoincrement": false
+ },
+ "actor_type": {
+ "name": "actor_type",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": "'system'"
+ },
+ "weight_profile_id": {
+ "name": "weight_profile_id",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": false,
+ "autoincrement": false
+ },
+ "evidence_json": {
+ "name": "evidence_json",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": "'{}'"
+ },
+ "reason": {
+ "name": "reason",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": "''"
+ },
+ "created_at": {
+ "name": "created_at",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": "CURRENT_TIMESTAMP"
+ }
+ },
+ "indexes": {
+ "world_events_candidate_idx": {
+ "name": "world_events_candidate_idx",
+ "columns": [
+ "candidate_id"
+ ],
+ "isUnique": false
+ }
+ },
+ "foreignKeys": {
+ "world_growth_events_candidate_id_world_category_candidates_id_fk": {
+ "name": "world_growth_events_candidate_id_world_category_candidates_id_fk",
+ "tableFrom": "world_growth_events",
+ "tableTo": "world_category_candidates",
+ "columnsFrom": [
+ "candidate_id"
+ ],
+ "columnsTo": [
+ "id"
+ ],
+ "onDelete": "cascade",
+ "onUpdate": "no action"
+ },
+ "world_growth_events_weight_profile_id_world_weight_profiles_id_fk": {
+ "name": "world_growth_events_weight_profile_id_world_weight_profiles_id_fk",
+ "tableFrom": "world_growth_events",
+ "tableTo": "world_weight_profiles",
+ "columnsFrom": [
+ "weight_profile_id"
+ ],
+ "columnsTo": [
+ "id"
+ ],
+ "onDelete": "no action",
+ "onUpdate": "no action"
+ }
+ },
+ "compositePrimaryKeys": {},
+ "uniqueConstraints": {},
+ "checkConstraints": {}
+ },
+ "world_signal_assignments": {
+ "name": "world_signal_assignments",
+ "columns": {
+ "id": {
+ "name": "id",
+ "type": "text",
+ "primaryKey": true,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "vault_id": {
+ "name": "vault_id",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "debt_id": {
+ "name": "debt_id",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "candidate_id": {
+ "name": "candidate_id",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "confidence": {
+ "name": "confidence",
+ "type": "real",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "assignment_source": {
+ "name": "assignment_source",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": "'ai'"
+ },
+ "taxonomy_version": {
+ "name": "taxonomy_version",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": 1
+ },
+ "created_at": {
+ "name": "created_at",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": "CURRENT_TIMESTAMP"
+ },
+ "updated_at": {
+ "name": "updated_at",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": "CURRENT_TIMESTAMP"
+ }
+ },
+ "indexes": {
+ "world_signal_assignments_debt_id_unique": {
+ "name": "world_signal_assignments_debt_id_unique",
+ "columns": [
+ "debt_id"
+ ],
+ "isUnique": true
+ },
+ "world_signals_vault_idx": {
+ "name": "world_signals_vault_idx",
+ "columns": [
+ "vault_id"
+ ],
+ "isUnique": false
+ },
+ "world_signals_candidate_idx": {
+ "name": "world_signals_candidate_idx",
+ "columns": [
+ "candidate_id"
+ ],
+ "isUnique": false
+ }
+ },
+ "foreignKeys": {
+ "world_signal_assignments_vault_id_vaults_id_fk": {
+ "name": "world_signal_assignments_vault_id_vaults_id_fk",
+ "tableFrom": "world_signal_assignments",
+ "tableTo": "vaults",
+ "columnsFrom": [
+ "vault_id"
+ ],
+ "columnsTo": [
+ "id"
+ ],
+ "onDelete": "cascade",
+ "onUpdate": "no action"
+ },
+ "world_signal_assignments_debt_id_debts_id_fk": {
+ "name": "world_signal_assignments_debt_id_debts_id_fk",
+ "tableFrom": "world_signal_assignments",
+ "tableTo": "debts",
+ "columnsFrom": [
+ "debt_id"
+ ],
+ "columnsTo": [
+ "id"
+ ],
+ "onDelete": "cascade",
+ "onUpdate": "no action"
+ },
+ "world_signal_assignments_candidate_id_world_category_candidates_id_fk": {
+ "name": "world_signal_assignments_candidate_id_world_category_candidates_id_fk",
+ "tableFrom": "world_signal_assignments",
+ "tableTo": "world_category_candidates",
+ "columnsFrom": [
+ "candidate_id"
+ ],
+ "columnsTo": [
+ "id"
+ ],
+ "onDelete": "cascade",
+ "onUpdate": "no action"
+ }
+ },
+ "compositePrimaryKeys": {},
+ "uniqueConstraints": {},
+ "checkConstraints": {}
+ },
+ "world_weight_profiles": {
+ "name": "world_weight_profiles",
+ "columns": {
+ "id": {
+ "name": "id",
+ "type": "text",
+ "primaryKey": true,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "version": {
+ "name": "version",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "status": {
+ "name": "status",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": "'draft'"
+ },
+ "frequency_weight": {
+ "name": "frequency_weight",
+ "type": "real",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "growth_weight": {
+ "name": "growth_weight",
+ "type": "real",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "geography_weight": {
+ "name": "geography_weight",
+ "type": "real",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "recurrence_weight": {
+ "name": "recurrence_weight",
+ "type": "real",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "connection_weight": {
+ "name": "connection_weight",
+ "type": "real",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "quality_weight": {
+ "name": "quality_weight",
+ "type": "real",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "proposed_by": {
+ "name": "proposed_by",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": "'human'"
+ },
+ "model_ref": {
+ "name": "model_ref",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": false,
+ "autoincrement": false
+ },
+ "rationale": {
+ "name": "rationale",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": "''"
+ },
+ "created_at": {
+ "name": "created_at",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": "CURRENT_TIMESTAMP"
+ },
+ "activated_at": {
+ "name": "activated_at",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": false,
+ "autoincrement": false
+ }
+ },
+ "indexes": {
+ "world_weight_profiles_version_unique": {
+ "name": "world_weight_profiles_version_unique",
+ "columns": [
+ "version"
+ ],
+ "isUnique": true
+ }
+ },
+ "foreignKeys": {},
+ "compositePrimaryKeys": {},
+ "uniqueConstraints": {},
+ "checkConstraints": {}
+ }
+ },
+ "views": {},
+ "enums": {},
+ "_meta": {
+ "schemas": {},
+ "tables": {},
+ "columns": {}
+ },
+ "internal": {
+ "indexes": {}
+ }
+}
\ No newline at end of file
diff --git a/drizzle/meta/0008_snapshot.json b/drizzle/meta/0008_snapshot.json
new file mode 100644
index 0000000..4c88049
--- /dev/null
+++ b/drizzle/meta/0008_snapshot.json
@@ -0,0 +1,1671 @@
+{
+ "version": "6",
+ "dialect": "sqlite",
+ "id": "c11c48fb-ae14-49b9-8f8d-c74b23ccd837",
+ "prevId": "462d69f3-3a66-4d4b-b26b-33eb4311a4cf",
+ "tables": {
+ "community_moderation_actions": {
+ "name": "community_moderation_actions",
+ "columns": {
+ "id": {
+ "name": "id",
+ "type": "text",
+ "primaryKey": true,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "story_id": {
+ "name": "story_id",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "actor_digest": {
+ "name": "actor_digest",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "action": {
+ "name": "action",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "from_status": {
+ "name": "from_status",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "to_status": {
+ "name": "to_status",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "note": {
+ "name": "note",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": "''"
+ },
+ "created_at": {
+ "name": "created_at",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": "CURRENT_TIMESTAMP"
+ }
+ },
+ "indexes": {
+ "community_moderation_story_idx": {
+ "name": "community_moderation_story_idx",
+ "columns": [
+ "story_id"
+ ],
+ "isUnique": false
+ },
+ "community_moderation_created_idx": {
+ "name": "community_moderation_created_idx",
+ "columns": [
+ "created_at"
+ ],
+ "isUnique": false
+ }
+ },
+ "foreignKeys": {
+ "community_moderation_actions_story_id_public_stories_id_fk": {
+ "name": "community_moderation_actions_story_id_public_stories_id_fk",
+ "tableFrom": "community_moderation_actions",
+ "tableTo": "public_stories",
+ "columnsFrom": [
+ "story_id"
+ ],
+ "columnsTo": [
+ "id"
+ ],
+ "onDelete": "cascade",
+ "onUpdate": "no action"
+ }
+ },
+ "compositePrimaryKeys": {},
+ "uniqueConstraints": {},
+ "checkConstraints": {}
+ },
+ "community_rate_limits": {
+ "name": "community_rate_limits",
+ "columns": {
+ "id": {
+ "name": "id",
+ "type": "text",
+ "primaryKey": true,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "vault_id": {
+ "name": "vault_id",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "action": {
+ "name": "action",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "window_key": {
+ "name": "window_key",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "count": {
+ "name": "count",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": 0
+ },
+ "updated_at": {
+ "name": "updated_at",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": "CURRENT_TIMESTAMP"
+ }
+ },
+ "indexes": {
+ "community_rate_vault_action_window_unique": {
+ "name": "community_rate_vault_action_window_unique",
+ "columns": [
+ "vault_id",
+ "action",
+ "window_key"
+ ],
+ "isUnique": true
+ },
+ "community_rate_window_idx": {
+ "name": "community_rate_window_idx",
+ "columns": [
+ "window_key"
+ ],
+ "isUnique": false
+ }
+ },
+ "foreignKeys": {
+ "community_rate_limits_vault_id_vaults_id_fk": {
+ "name": "community_rate_limits_vault_id_vaults_id_fk",
+ "tableFrom": "community_rate_limits",
+ "tableTo": "vaults",
+ "columnsFrom": [
+ "vault_id"
+ ],
+ "columnsTo": [
+ "id"
+ ],
+ "onDelete": "cascade",
+ "onUpdate": "no action"
+ }
+ },
+ "compositePrimaryKeys": {},
+ "uniqueConstraints": {},
+ "checkConstraints": {}
+ },
+ "debts": {
+ "name": "debts",
+ "columns": {
+ "id": {
+ "name": "id",
+ "type": "text",
+ "primaryKey": true,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "vault_id": {
+ "name": "vault_id",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "kind": {
+ "name": "kind",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "custom_label": {
+ "name": "custom_label",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": false,
+ "autoincrement": false
+ },
+ "currency": {
+ "name": "currency",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "original": {
+ "name": "original",
+ "type": "real",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "balance": {
+ "name": "balance",
+ "type": "real",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "monthly": {
+ "name": "monthly",
+ "type": "real",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "due_day": {
+ "name": "due_day",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "method": {
+ "name": "method",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "sharing_mode": {
+ "name": "sharing_mode",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": "'private'"
+ },
+ "last_paid_at": {
+ "name": "last_paid_at",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": false,
+ "autoincrement": false
+ },
+ "payments": {
+ "name": "payments",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": 0
+ },
+ "created_at": {
+ "name": "created_at",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": "CURRENT_TIMESTAMP"
+ },
+ "updated_at": {
+ "name": "updated_at",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": "CURRENT_TIMESTAMP"
+ }
+ },
+ "indexes": {
+ "debts_vault_id_idx": {
+ "name": "debts_vault_id_idx",
+ "columns": [
+ "vault_id"
+ ],
+ "isUnique": false
+ }
+ },
+ "foreignKeys": {
+ "debts_vault_id_vaults_id_fk": {
+ "name": "debts_vault_id_vaults_id_fk",
+ "tableFrom": "debts",
+ "tableTo": "vaults",
+ "columnsFrom": [
+ "vault_id"
+ ],
+ "columnsTo": [
+ "id"
+ ],
+ "onDelete": "cascade",
+ "onUpdate": "no action"
+ }
+ },
+ "compositePrimaryKeys": {},
+ "uniqueConstraints": {},
+ "checkConstraints": {}
+ },
+ "lucky_income_claims": {
+ "name": "lucky_income_claims",
+ "columns": {
+ "id": {
+ "name": "id",
+ "type": "text",
+ "primaryKey": true,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "vault_id": {
+ "name": "vault_id",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "event_date": {
+ "name": "event_date",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "created_at": {
+ "name": "created_at",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": "CURRENT_TIMESTAMP"
+ }
+ },
+ "indexes": {
+ "lucky_income_vault_day_unique": {
+ "name": "lucky_income_vault_day_unique",
+ "columns": [
+ "vault_id",
+ "event_date"
+ ],
+ "isUnique": true
+ }
+ },
+ "foreignKeys": {
+ "lucky_income_claims_vault_id_vaults_id_fk": {
+ "name": "lucky_income_claims_vault_id_vaults_id_fk",
+ "tableFrom": "lucky_income_claims",
+ "tableTo": "vaults",
+ "columnsFrom": [
+ "vault_id"
+ ],
+ "columnsTo": [
+ "id"
+ ],
+ "onDelete": "cascade",
+ "onUpdate": "no action"
+ }
+ },
+ "compositePrimaryKeys": {},
+ "uniqueConstraints": {},
+ "checkConstraints": {}
+ },
+ "payment_records": {
+ "name": "payment_records",
+ "columns": {
+ "id": {
+ "name": "id",
+ "type": "text",
+ "primaryKey": true,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "vault_id": {
+ "name": "vault_id",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "debt_id": {
+ "name": "debt_id",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "scheduled_date": {
+ "name": "scheduled_date",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": false,
+ "autoincrement": false
+ },
+ "confirmed_at": {
+ "name": "confirmed_at",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "event_date": {
+ "name": "event_date",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": false,
+ "autoincrement": false
+ },
+ "cash_payment": {
+ "name": "cash_payment",
+ "type": "real",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "new_balance": {
+ "name": "new_balance",
+ "type": "real",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "source": {
+ "name": "source",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": "'self_report'"
+ },
+ "income_type": {
+ "name": "income_type",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": false,
+ "autoincrement": false
+ },
+ "created_at": {
+ "name": "created_at",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": "CURRENT_TIMESTAMP"
+ }
+ },
+ "indexes": {
+ "payments_vault_id_idx": {
+ "name": "payments_vault_id_idx",
+ "columns": [
+ "vault_id"
+ ],
+ "isUnique": false
+ },
+ "payments_debt_id_idx": {
+ "name": "payments_debt_id_idx",
+ "columns": [
+ "debt_id"
+ ],
+ "isUnique": false
+ }
+ },
+ "foreignKeys": {
+ "payment_records_vault_id_vaults_id_fk": {
+ "name": "payment_records_vault_id_vaults_id_fk",
+ "tableFrom": "payment_records",
+ "tableTo": "vaults",
+ "columnsFrom": [
+ "vault_id"
+ ],
+ "columnsTo": [
+ "id"
+ ],
+ "onDelete": "cascade",
+ "onUpdate": "no action"
+ },
+ "payment_records_debt_id_debts_id_fk": {
+ "name": "payment_records_debt_id_debts_id_fk",
+ "tableFrom": "payment_records",
+ "tableTo": "debts",
+ "columnsFrom": [
+ "debt_id"
+ ],
+ "columnsTo": [
+ "id"
+ ],
+ "onDelete": "cascade",
+ "onUpdate": "no action"
+ }
+ },
+ "compositePrimaryKeys": {},
+ "uniqueConstraints": {},
+ "checkConstraints": {}
+ },
+ "policy_acceptances": {
+ "name": "policy_acceptances",
+ "columns": {
+ "id": {
+ "name": "id",
+ "type": "text",
+ "primaryKey": true,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "vault_id": {
+ "name": "vault_id",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "policy_key": {
+ "name": "policy_key",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "policy_version": {
+ "name": "policy_version",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "accepted_at": {
+ "name": "accepted_at",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": "CURRENT_TIMESTAMP"
+ }
+ },
+ "indexes": {
+ "policy_acceptance_vault_key_version_unique": {
+ "name": "policy_acceptance_vault_key_version_unique",
+ "columns": [
+ "vault_id",
+ "policy_key",
+ "policy_version"
+ ],
+ "isUnique": true
+ },
+ "policy_acceptance_vault_idx": {
+ "name": "policy_acceptance_vault_idx",
+ "columns": [
+ "vault_id"
+ ],
+ "isUnique": false
+ }
+ },
+ "foreignKeys": {
+ "policy_acceptances_vault_id_vaults_id_fk": {
+ "name": "policy_acceptances_vault_id_vaults_id_fk",
+ "tableFrom": "policy_acceptances",
+ "tableTo": "vaults",
+ "columnsFrom": [
+ "vault_id"
+ ],
+ "columnsTo": [
+ "id"
+ ],
+ "onDelete": "cascade",
+ "onUpdate": "no action"
+ }
+ },
+ "compositePrimaryKeys": {},
+ "uniqueConstraints": {},
+ "checkConstraints": {}
+ },
+ "public_stories": {
+ "name": "public_stories",
+ "columns": {
+ "id": {
+ "name": "id",
+ "type": "text",
+ "primaryKey": true,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "vault_id": {
+ "name": "vault_id",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "debt_id": {
+ "name": "debt_id",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "anonymous_name": {
+ "name": "anonymous_name",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "country_code": {
+ "name": "country_code",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": "''"
+ },
+ "debt_kind": {
+ "name": "debt_kind",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "amount_band": {
+ "name": "amount_band",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "currency": {
+ "name": "currency",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "repayment_approach": {
+ "name": "repayment_approach",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": "'other'"
+ },
+ "story_text": {
+ "name": "story_text",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "status": {
+ "name": "status",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": "'pending'"
+ },
+ "created_at": {
+ "name": "created_at",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": "CURRENT_TIMESTAMP"
+ },
+ "updated_at": {
+ "name": "updated_at",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": "CURRENT_TIMESTAMP"
+ }
+ },
+ "indexes": {
+ "public_stories_status_idx": {
+ "name": "public_stories_status_idx",
+ "columns": [
+ "status"
+ ],
+ "isUnique": false
+ },
+ "public_stories_vault_idx": {
+ "name": "public_stories_vault_idx",
+ "columns": [
+ "vault_id"
+ ],
+ "isUnique": false
+ }
+ },
+ "foreignKeys": {
+ "public_stories_vault_id_vaults_id_fk": {
+ "name": "public_stories_vault_id_vaults_id_fk",
+ "tableFrom": "public_stories",
+ "tableTo": "vaults",
+ "columnsFrom": [
+ "vault_id"
+ ],
+ "columnsTo": [
+ "id"
+ ],
+ "onDelete": "cascade",
+ "onUpdate": "no action"
+ },
+ "public_stories_debt_id_debts_id_fk": {
+ "name": "public_stories_debt_id_debts_id_fk",
+ "tableFrom": "public_stories",
+ "tableTo": "debts",
+ "columnsFrom": [
+ "debt_id"
+ ],
+ "columnsTo": [
+ "id"
+ ],
+ "onDelete": "cascade",
+ "onUpdate": "no action"
+ }
+ },
+ "compositePrimaryKeys": {},
+ "uniqueConstraints": {},
+ "checkConstraints": {}
+ },
+ "story_encouragements": {
+ "name": "story_encouragements",
+ "columns": {
+ "id": {
+ "name": "id",
+ "type": "text",
+ "primaryKey": true,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "story_id": {
+ "name": "story_id",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "vault_id": {
+ "name": "vault_id",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "created_at": {
+ "name": "created_at",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": "CURRENT_TIMESTAMP"
+ }
+ },
+ "indexes": {
+ "story_encouragement_unique": {
+ "name": "story_encouragement_unique",
+ "columns": [
+ "story_id",
+ "vault_id"
+ ],
+ "isUnique": true
+ },
+ "story_encouragement_story_idx": {
+ "name": "story_encouragement_story_idx",
+ "columns": [
+ "story_id"
+ ],
+ "isUnique": false
+ }
+ },
+ "foreignKeys": {
+ "story_encouragements_story_id_public_stories_id_fk": {
+ "name": "story_encouragements_story_id_public_stories_id_fk",
+ "tableFrom": "story_encouragements",
+ "tableTo": "public_stories",
+ "columnsFrom": [
+ "story_id"
+ ],
+ "columnsTo": [
+ "id"
+ ],
+ "onDelete": "cascade",
+ "onUpdate": "no action"
+ },
+ "story_encouragements_vault_id_vaults_id_fk": {
+ "name": "story_encouragements_vault_id_vaults_id_fk",
+ "tableFrom": "story_encouragements",
+ "tableTo": "vaults",
+ "columnsFrom": [
+ "vault_id"
+ ],
+ "columnsTo": [
+ "id"
+ ],
+ "onDelete": "cascade",
+ "onUpdate": "no action"
+ }
+ },
+ "compositePrimaryKeys": {},
+ "uniqueConstraints": {},
+ "checkConstraints": {}
+ },
+ "story_reports": {
+ "name": "story_reports",
+ "columns": {
+ "id": {
+ "name": "id",
+ "type": "text",
+ "primaryKey": true,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "story_id": {
+ "name": "story_id",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "reporter_vault_id": {
+ "name": "reporter_vault_id",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "reason": {
+ "name": "reason",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "details": {
+ "name": "details",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": "''"
+ },
+ "status": {
+ "name": "status",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": "'open'"
+ },
+ "created_at": {
+ "name": "created_at",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": "CURRENT_TIMESTAMP"
+ },
+ "resolved_at": {
+ "name": "resolved_at",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": false,
+ "autoincrement": false
+ }
+ },
+ "indexes": {
+ "story_report_unique": {
+ "name": "story_report_unique",
+ "columns": [
+ "story_id",
+ "reporter_vault_id"
+ ],
+ "isUnique": true
+ },
+ "story_reports_status_idx": {
+ "name": "story_reports_status_idx",
+ "columns": [
+ "status"
+ ],
+ "isUnique": false
+ }
+ },
+ "foreignKeys": {
+ "story_reports_story_id_public_stories_id_fk": {
+ "name": "story_reports_story_id_public_stories_id_fk",
+ "tableFrom": "story_reports",
+ "tableTo": "public_stories",
+ "columnsFrom": [
+ "story_id"
+ ],
+ "columnsTo": [
+ "id"
+ ],
+ "onDelete": "cascade",
+ "onUpdate": "no action"
+ },
+ "story_reports_reporter_vault_id_vaults_id_fk": {
+ "name": "story_reports_reporter_vault_id_vaults_id_fk",
+ "tableFrom": "story_reports",
+ "tableTo": "vaults",
+ "columnsFrom": [
+ "reporter_vault_id"
+ ],
+ "columnsTo": [
+ "id"
+ ],
+ "onDelete": "cascade",
+ "onUpdate": "no action"
+ }
+ },
+ "compositePrimaryKeys": {},
+ "uniqueConstraints": {},
+ "checkConstraints": {}
+ },
+ "vaults": {
+ "name": "vaults",
+ "columns": {
+ "id": {
+ "name": "id",
+ "type": "text",
+ "primaryKey": true,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "recovery_hash": {
+ "name": "recovery_hash",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "alias": {
+ "name": "alias",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "region": {
+ "name": "region",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "pressure": {
+ "name": "pressure",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": "''"
+ },
+ "position_x": {
+ "name": "position_x",
+ "type": "real",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": 47
+ },
+ "position_y": {
+ "name": "position_y",
+ "type": "real",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": 63
+ },
+ "locale": {
+ "name": "locale",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": "'zh'"
+ },
+ "country_code": {
+ "name": "country_code",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": "''"
+ },
+ "country_name": {
+ "name": "country_name",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": "''"
+ },
+ "display_currency": {
+ "name": "display_currency",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": "'CNY'"
+ },
+ "monthly_income": {
+ "name": "monthly_income",
+ "type": "real",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": 0
+ },
+ "monthly_expenses": {
+ "name": "monthly_expenses",
+ "type": "real",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": 0
+ },
+ "discovery_consent": {
+ "name": "discovery_consent",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": false
+ },
+ "created_at": {
+ "name": "created_at",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": "CURRENT_TIMESTAMP"
+ },
+ "updated_at": {
+ "name": "updated_at",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": "CURRENT_TIMESTAMP"
+ }
+ },
+ "indexes": {
+ "vaults_recovery_hash_unique": {
+ "name": "vaults_recovery_hash_unique",
+ "columns": [
+ "recovery_hash"
+ ],
+ "isUnique": true
+ }
+ },
+ "foreignKeys": {},
+ "compositePrimaryKeys": {},
+ "uniqueConstraints": {},
+ "checkConstraints": {}
+ },
+ "world_category_candidates": {
+ "name": "world_category_candidates",
+ "columns": {
+ "id": {
+ "name": "id",
+ "type": "text",
+ "primaryKey": true,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "canonical_key": {
+ "name": "canonical_key",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "parent_kind": {
+ "name": "parent_kind",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": "'other'"
+ },
+ "name_zh": {
+ "name": "name_zh",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "name_en": {
+ "name": "name_en",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "description_zh": {
+ "name": "description_zh",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": "''"
+ },
+ "description_en": {
+ "name": "description_en",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": "''"
+ },
+ "status": {
+ "name": "status",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": "'candidate'"
+ },
+ "stage": {
+ "name": "stage",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": 0
+ },
+ "confidence": {
+ "name": "confidence",
+ "type": "real",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": 0
+ },
+ "unique_vaults": {
+ "name": "unique_vaults",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": 0
+ },
+ "region_count": {
+ "name": "region_count",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": 0
+ },
+ "mention_count": {
+ "name": "mention_count",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": 0
+ },
+ "emergence_score": {
+ "name": "emergence_score",
+ "type": "real",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": 0
+ },
+ "weight_profile_id": {
+ "name": "weight_profile_id",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": false,
+ "autoincrement": false
+ },
+ "merged_into_id": {
+ "name": "merged_into_id",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": false,
+ "autoincrement": false
+ },
+ "proposed_at": {
+ "name": "proposed_at",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": "CURRENT_TIMESTAMP"
+ },
+ "reviewed_at": {
+ "name": "reviewed_at",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": false,
+ "autoincrement": false
+ },
+ "published_at": {
+ "name": "published_at",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": false,
+ "autoincrement": false
+ },
+ "updated_at": {
+ "name": "updated_at",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": "CURRENT_TIMESTAMP"
+ }
+ },
+ "indexes": {
+ "world_category_candidates_canonical_key_unique": {
+ "name": "world_category_candidates_canonical_key_unique",
+ "columns": [
+ "canonical_key"
+ ],
+ "isUnique": true
+ },
+ "world_candidates_status_idx": {
+ "name": "world_candidates_status_idx",
+ "columns": [
+ "status"
+ ],
+ "isUnique": false
+ },
+ "world_candidates_score_idx": {
+ "name": "world_candidates_score_idx",
+ "columns": [
+ "emergence_score"
+ ],
+ "isUnique": false
+ }
+ },
+ "foreignKeys": {
+ "world_category_candidates_weight_profile_id_world_weight_profiles_id_fk": {
+ "name": "world_category_candidates_weight_profile_id_world_weight_profiles_id_fk",
+ "tableFrom": "world_category_candidates",
+ "tableTo": "world_weight_profiles",
+ "columnsFrom": [
+ "weight_profile_id"
+ ],
+ "columnsTo": [
+ "id"
+ ],
+ "onDelete": "no action",
+ "onUpdate": "no action"
+ }
+ },
+ "compositePrimaryKeys": {},
+ "uniqueConstraints": {},
+ "checkConstraints": {}
+ },
+ "world_growth_events": {
+ "name": "world_growth_events",
+ "columns": {
+ "id": {
+ "name": "id",
+ "type": "text",
+ "primaryKey": true,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "candidate_id": {
+ "name": "candidate_id",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "event_type": {
+ "name": "event_type",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "from_stage": {
+ "name": "from_stage",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": false,
+ "autoincrement": false
+ },
+ "to_stage": {
+ "name": "to_stage",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": false,
+ "autoincrement": false
+ },
+ "actor_type": {
+ "name": "actor_type",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": "'system'"
+ },
+ "weight_profile_id": {
+ "name": "weight_profile_id",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": false,
+ "autoincrement": false
+ },
+ "evidence_json": {
+ "name": "evidence_json",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": "'{}'"
+ },
+ "reason": {
+ "name": "reason",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": "''"
+ },
+ "created_at": {
+ "name": "created_at",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": "CURRENT_TIMESTAMP"
+ }
+ },
+ "indexes": {
+ "world_events_candidate_idx": {
+ "name": "world_events_candidate_idx",
+ "columns": [
+ "candidate_id"
+ ],
+ "isUnique": false
+ }
+ },
+ "foreignKeys": {
+ "world_growth_events_candidate_id_world_category_candidates_id_fk": {
+ "name": "world_growth_events_candidate_id_world_category_candidates_id_fk",
+ "tableFrom": "world_growth_events",
+ "tableTo": "world_category_candidates",
+ "columnsFrom": [
+ "candidate_id"
+ ],
+ "columnsTo": [
+ "id"
+ ],
+ "onDelete": "cascade",
+ "onUpdate": "no action"
+ },
+ "world_growth_events_weight_profile_id_world_weight_profiles_id_fk": {
+ "name": "world_growth_events_weight_profile_id_world_weight_profiles_id_fk",
+ "tableFrom": "world_growth_events",
+ "tableTo": "world_weight_profiles",
+ "columnsFrom": [
+ "weight_profile_id"
+ ],
+ "columnsTo": [
+ "id"
+ ],
+ "onDelete": "no action",
+ "onUpdate": "no action"
+ }
+ },
+ "compositePrimaryKeys": {},
+ "uniqueConstraints": {},
+ "checkConstraints": {}
+ },
+ "world_signal_assignments": {
+ "name": "world_signal_assignments",
+ "columns": {
+ "id": {
+ "name": "id",
+ "type": "text",
+ "primaryKey": true,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "vault_id": {
+ "name": "vault_id",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "debt_id": {
+ "name": "debt_id",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "candidate_id": {
+ "name": "candidate_id",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "confidence": {
+ "name": "confidence",
+ "type": "real",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "assignment_source": {
+ "name": "assignment_source",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": "'ai'"
+ },
+ "taxonomy_version": {
+ "name": "taxonomy_version",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": 1
+ },
+ "created_at": {
+ "name": "created_at",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": "CURRENT_TIMESTAMP"
+ },
+ "updated_at": {
+ "name": "updated_at",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": "CURRENT_TIMESTAMP"
+ }
+ },
+ "indexes": {
+ "world_signal_assignments_debt_id_unique": {
+ "name": "world_signal_assignments_debt_id_unique",
+ "columns": [
+ "debt_id"
+ ],
+ "isUnique": true
+ },
+ "world_signals_vault_idx": {
+ "name": "world_signals_vault_idx",
+ "columns": [
+ "vault_id"
+ ],
+ "isUnique": false
+ },
+ "world_signals_candidate_idx": {
+ "name": "world_signals_candidate_idx",
+ "columns": [
+ "candidate_id"
+ ],
+ "isUnique": false
+ }
+ },
+ "foreignKeys": {
+ "world_signal_assignments_vault_id_vaults_id_fk": {
+ "name": "world_signal_assignments_vault_id_vaults_id_fk",
+ "tableFrom": "world_signal_assignments",
+ "tableTo": "vaults",
+ "columnsFrom": [
+ "vault_id"
+ ],
+ "columnsTo": [
+ "id"
+ ],
+ "onDelete": "cascade",
+ "onUpdate": "no action"
+ },
+ "world_signal_assignments_debt_id_debts_id_fk": {
+ "name": "world_signal_assignments_debt_id_debts_id_fk",
+ "tableFrom": "world_signal_assignments",
+ "tableTo": "debts",
+ "columnsFrom": [
+ "debt_id"
+ ],
+ "columnsTo": [
+ "id"
+ ],
+ "onDelete": "cascade",
+ "onUpdate": "no action"
+ },
+ "world_signal_assignments_candidate_id_world_category_candidates_id_fk": {
+ "name": "world_signal_assignments_candidate_id_world_category_candidates_id_fk",
+ "tableFrom": "world_signal_assignments",
+ "tableTo": "world_category_candidates",
+ "columnsFrom": [
+ "candidate_id"
+ ],
+ "columnsTo": [
+ "id"
+ ],
+ "onDelete": "cascade",
+ "onUpdate": "no action"
+ }
+ },
+ "compositePrimaryKeys": {},
+ "uniqueConstraints": {},
+ "checkConstraints": {}
+ },
+ "world_weight_profiles": {
+ "name": "world_weight_profiles",
+ "columns": {
+ "id": {
+ "name": "id",
+ "type": "text",
+ "primaryKey": true,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "version": {
+ "name": "version",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "status": {
+ "name": "status",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": "'draft'"
+ },
+ "frequency_weight": {
+ "name": "frequency_weight",
+ "type": "real",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "growth_weight": {
+ "name": "growth_weight",
+ "type": "real",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "geography_weight": {
+ "name": "geography_weight",
+ "type": "real",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "recurrence_weight": {
+ "name": "recurrence_weight",
+ "type": "real",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "connection_weight": {
+ "name": "connection_weight",
+ "type": "real",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "quality_weight": {
+ "name": "quality_weight",
+ "type": "real",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "proposed_by": {
+ "name": "proposed_by",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": "'human'"
+ },
+ "model_ref": {
+ "name": "model_ref",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": false,
+ "autoincrement": false
+ },
+ "rationale": {
+ "name": "rationale",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": "''"
+ },
+ "created_at": {
+ "name": "created_at",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": "CURRENT_TIMESTAMP"
+ },
+ "activated_at": {
+ "name": "activated_at",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": false,
+ "autoincrement": false
+ }
+ },
+ "indexes": {
+ "world_weight_profiles_version_unique": {
+ "name": "world_weight_profiles_version_unique",
+ "columns": [
+ "version"
+ ],
+ "isUnique": true
+ }
+ },
+ "foreignKeys": {},
+ "compositePrimaryKeys": {},
+ "uniqueConstraints": {},
+ "checkConstraints": {}
+ }
+ },
+ "views": {},
+ "enums": {},
+ "_meta": {
+ "schemas": {},
+ "tables": {},
+ "columns": {}
+ },
+ "internal": {
+ "indexes": {}
+ }
+}
\ No newline at end of file
diff --git a/drizzle/meta/0009_snapshot.json b/drizzle/meta/0009_snapshot.json
new file mode 100644
index 0000000..b4794e8
--- /dev/null
+++ b/drizzle/meta/0009_snapshot.json
@@ -0,0 +1,1764 @@
+{
+ "version": "6",
+ "dialect": "sqlite",
+ "id": "96353f86-7864-411e-96d8-495bde164d74",
+ "prevId": "c11c48fb-ae14-49b9-8f8d-c74b23ccd837",
+ "tables": {
+ "ai_daily_usage": {
+ "name": "ai_daily_usage",
+ "columns": {
+ "id": {
+ "name": "id",
+ "type": "text",
+ "primaryKey": true,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "vault_id": {
+ "name": "vault_id",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "usage_date": {
+ "name": "usage_date",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "request_count": {
+ "name": "request_count",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": 0
+ },
+ "input_tokens": {
+ "name": "input_tokens",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": 0
+ },
+ "output_tokens": {
+ "name": "output_tokens",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": 0
+ },
+ "updated_at": {
+ "name": "updated_at",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": "CURRENT_TIMESTAMP"
+ }
+ },
+ "indexes": {
+ "ai_daily_usage_vault_date_unique": {
+ "name": "ai_daily_usage_vault_date_unique",
+ "columns": [
+ "vault_id",
+ "usage_date"
+ ],
+ "isUnique": true
+ },
+ "ai_daily_usage_date_idx": {
+ "name": "ai_daily_usage_date_idx",
+ "columns": [
+ "usage_date"
+ ],
+ "isUnique": false
+ }
+ },
+ "foreignKeys": {
+ "ai_daily_usage_vault_id_vaults_id_fk": {
+ "name": "ai_daily_usage_vault_id_vaults_id_fk",
+ "tableFrom": "ai_daily_usage",
+ "tableTo": "vaults",
+ "columnsFrom": [
+ "vault_id"
+ ],
+ "columnsTo": [
+ "id"
+ ],
+ "onDelete": "cascade",
+ "onUpdate": "no action"
+ }
+ },
+ "compositePrimaryKeys": {},
+ "uniqueConstraints": {},
+ "checkConstraints": {}
+ },
+ "community_moderation_actions": {
+ "name": "community_moderation_actions",
+ "columns": {
+ "id": {
+ "name": "id",
+ "type": "text",
+ "primaryKey": true,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "story_id": {
+ "name": "story_id",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "actor_digest": {
+ "name": "actor_digest",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "action": {
+ "name": "action",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "from_status": {
+ "name": "from_status",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "to_status": {
+ "name": "to_status",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "note": {
+ "name": "note",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": "''"
+ },
+ "created_at": {
+ "name": "created_at",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": "CURRENT_TIMESTAMP"
+ }
+ },
+ "indexes": {
+ "community_moderation_story_idx": {
+ "name": "community_moderation_story_idx",
+ "columns": [
+ "story_id"
+ ],
+ "isUnique": false
+ },
+ "community_moderation_created_idx": {
+ "name": "community_moderation_created_idx",
+ "columns": [
+ "created_at"
+ ],
+ "isUnique": false
+ }
+ },
+ "foreignKeys": {
+ "community_moderation_actions_story_id_public_stories_id_fk": {
+ "name": "community_moderation_actions_story_id_public_stories_id_fk",
+ "tableFrom": "community_moderation_actions",
+ "tableTo": "public_stories",
+ "columnsFrom": [
+ "story_id"
+ ],
+ "columnsTo": [
+ "id"
+ ],
+ "onDelete": "cascade",
+ "onUpdate": "no action"
+ }
+ },
+ "compositePrimaryKeys": {},
+ "uniqueConstraints": {},
+ "checkConstraints": {}
+ },
+ "community_rate_limits": {
+ "name": "community_rate_limits",
+ "columns": {
+ "id": {
+ "name": "id",
+ "type": "text",
+ "primaryKey": true,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "vault_id": {
+ "name": "vault_id",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "action": {
+ "name": "action",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "window_key": {
+ "name": "window_key",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "count": {
+ "name": "count",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": 0
+ },
+ "updated_at": {
+ "name": "updated_at",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": "CURRENT_TIMESTAMP"
+ }
+ },
+ "indexes": {
+ "community_rate_vault_action_window_unique": {
+ "name": "community_rate_vault_action_window_unique",
+ "columns": [
+ "vault_id",
+ "action",
+ "window_key"
+ ],
+ "isUnique": true
+ },
+ "community_rate_window_idx": {
+ "name": "community_rate_window_idx",
+ "columns": [
+ "window_key"
+ ],
+ "isUnique": false
+ }
+ },
+ "foreignKeys": {
+ "community_rate_limits_vault_id_vaults_id_fk": {
+ "name": "community_rate_limits_vault_id_vaults_id_fk",
+ "tableFrom": "community_rate_limits",
+ "tableTo": "vaults",
+ "columnsFrom": [
+ "vault_id"
+ ],
+ "columnsTo": [
+ "id"
+ ],
+ "onDelete": "cascade",
+ "onUpdate": "no action"
+ }
+ },
+ "compositePrimaryKeys": {},
+ "uniqueConstraints": {},
+ "checkConstraints": {}
+ },
+ "debts": {
+ "name": "debts",
+ "columns": {
+ "id": {
+ "name": "id",
+ "type": "text",
+ "primaryKey": true,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "vault_id": {
+ "name": "vault_id",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "kind": {
+ "name": "kind",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "custom_label": {
+ "name": "custom_label",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": false,
+ "autoincrement": false
+ },
+ "currency": {
+ "name": "currency",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "original": {
+ "name": "original",
+ "type": "real",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "balance": {
+ "name": "balance",
+ "type": "real",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "monthly": {
+ "name": "monthly",
+ "type": "real",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "due_day": {
+ "name": "due_day",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "method": {
+ "name": "method",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "sharing_mode": {
+ "name": "sharing_mode",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": "'private'"
+ },
+ "last_paid_at": {
+ "name": "last_paid_at",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": false,
+ "autoincrement": false
+ },
+ "payments": {
+ "name": "payments",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": 0
+ },
+ "created_at": {
+ "name": "created_at",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": "CURRENT_TIMESTAMP"
+ },
+ "updated_at": {
+ "name": "updated_at",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": "CURRENT_TIMESTAMP"
+ }
+ },
+ "indexes": {
+ "debts_vault_id_idx": {
+ "name": "debts_vault_id_idx",
+ "columns": [
+ "vault_id"
+ ],
+ "isUnique": false
+ }
+ },
+ "foreignKeys": {
+ "debts_vault_id_vaults_id_fk": {
+ "name": "debts_vault_id_vaults_id_fk",
+ "tableFrom": "debts",
+ "tableTo": "vaults",
+ "columnsFrom": [
+ "vault_id"
+ ],
+ "columnsTo": [
+ "id"
+ ],
+ "onDelete": "cascade",
+ "onUpdate": "no action"
+ }
+ },
+ "compositePrimaryKeys": {},
+ "uniqueConstraints": {},
+ "checkConstraints": {}
+ },
+ "lucky_income_claims": {
+ "name": "lucky_income_claims",
+ "columns": {
+ "id": {
+ "name": "id",
+ "type": "text",
+ "primaryKey": true,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "vault_id": {
+ "name": "vault_id",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "event_date": {
+ "name": "event_date",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "created_at": {
+ "name": "created_at",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": "CURRENT_TIMESTAMP"
+ }
+ },
+ "indexes": {
+ "lucky_income_vault_day_unique": {
+ "name": "lucky_income_vault_day_unique",
+ "columns": [
+ "vault_id",
+ "event_date"
+ ],
+ "isUnique": true
+ }
+ },
+ "foreignKeys": {
+ "lucky_income_claims_vault_id_vaults_id_fk": {
+ "name": "lucky_income_claims_vault_id_vaults_id_fk",
+ "tableFrom": "lucky_income_claims",
+ "tableTo": "vaults",
+ "columnsFrom": [
+ "vault_id"
+ ],
+ "columnsTo": [
+ "id"
+ ],
+ "onDelete": "cascade",
+ "onUpdate": "no action"
+ }
+ },
+ "compositePrimaryKeys": {},
+ "uniqueConstraints": {},
+ "checkConstraints": {}
+ },
+ "payment_records": {
+ "name": "payment_records",
+ "columns": {
+ "id": {
+ "name": "id",
+ "type": "text",
+ "primaryKey": true,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "vault_id": {
+ "name": "vault_id",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "debt_id": {
+ "name": "debt_id",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "scheduled_date": {
+ "name": "scheduled_date",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": false,
+ "autoincrement": false
+ },
+ "confirmed_at": {
+ "name": "confirmed_at",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "event_date": {
+ "name": "event_date",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": false,
+ "autoincrement": false
+ },
+ "cash_payment": {
+ "name": "cash_payment",
+ "type": "real",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "new_balance": {
+ "name": "new_balance",
+ "type": "real",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "source": {
+ "name": "source",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": "'self_report'"
+ },
+ "income_type": {
+ "name": "income_type",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": false,
+ "autoincrement": false
+ },
+ "created_at": {
+ "name": "created_at",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": "CURRENT_TIMESTAMP"
+ }
+ },
+ "indexes": {
+ "payments_vault_id_idx": {
+ "name": "payments_vault_id_idx",
+ "columns": [
+ "vault_id"
+ ],
+ "isUnique": false
+ },
+ "payments_debt_id_idx": {
+ "name": "payments_debt_id_idx",
+ "columns": [
+ "debt_id"
+ ],
+ "isUnique": false
+ }
+ },
+ "foreignKeys": {
+ "payment_records_vault_id_vaults_id_fk": {
+ "name": "payment_records_vault_id_vaults_id_fk",
+ "tableFrom": "payment_records",
+ "tableTo": "vaults",
+ "columnsFrom": [
+ "vault_id"
+ ],
+ "columnsTo": [
+ "id"
+ ],
+ "onDelete": "cascade",
+ "onUpdate": "no action"
+ },
+ "payment_records_debt_id_debts_id_fk": {
+ "name": "payment_records_debt_id_debts_id_fk",
+ "tableFrom": "payment_records",
+ "tableTo": "debts",
+ "columnsFrom": [
+ "debt_id"
+ ],
+ "columnsTo": [
+ "id"
+ ],
+ "onDelete": "cascade",
+ "onUpdate": "no action"
+ }
+ },
+ "compositePrimaryKeys": {},
+ "uniqueConstraints": {},
+ "checkConstraints": {}
+ },
+ "policy_acceptances": {
+ "name": "policy_acceptances",
+ "columns": {
+ "id": {
+ "name": "id",
+ "type": "text",
+ "primaryKey": true,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "vault_id": {
+ "name": "vault_id",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "policy_key": {
+ "name": "policy_key",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "policy_version": {
+ "name": "policy_version",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "accepted_at": {
+ "name": "accepted_at",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": "CURRENT_TIMESTAMP"
+ }
+ },
+ "indexes": {
+ "policy_acceptance_vault_key_version_unique": {
+ "name": "policy_acceptance_vault_key_version_unique",
+ "columns": [
+ "vault_id",
+ "policy_key",
+ "policy_version"
+ ],
+ "isUnique": true
+ },
+ "policy_acceptance_vault_idx": {
+ "name": "policy_acceptance_vault_idx",
+ "columns": [
+ "vault_id"
+ ],
+ "isUnique": false
+ }
+ },
+ "foreignKeys": {
+ "policy_acceptances_vault_id_vaults_id_fk": {
+ "name": "policy_acceptances_vault_id_vaults_id_fk",
+ "tableFrom": "policy_acceptances",
+ "tableTo": "vaults",
+ "columnsFrom": [
+ "vault_id"
+ ],
+ "columnsTo": [
+ "id"
+ ],
+ "onDelete": "cascade",
+ "onUpdate": "no action"
+ }
+ },
+ "compositePrimaryKeys": {},
+ "uniqueConstraints": {},
+ "checkConstraints": {}
+ },
+ "public_stories": {
+ "name": "public_stories",
+ "columns": {
+ "id": {
+ "name": "id",
+ "type": "text",
+ "primaryKey": true,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "vault_id": {
+ "name": "vault_id",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "debt_id": {
+ "name": "debt_id",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "anonymous_name": {
+ "name": "anonymous_name",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "country_code": {
+ "name": "country_code",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": "''"
+ },
+ "debt_kind": {
+ "name": "debt_kind",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "amount_band": {
+ "name": "amount_band",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "currency": {
+ "name": "currency",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "repayment_approach": {
+ "name": "repayment_approach",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": "'other'"
+ },
+ "story_text": {
+ "name": "story_text",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "status": {
+ "name": "status",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": "'pending'"
+ },
+ "created_at": {
+ "name": "created_at",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": "CURRENT_TIMESTAMP"
+ },
+ "updated_at": {
+ "name": "updated_at",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": "CURRENT_TIMESTAMP"
+ }
+ },
+ "indexes": {
+ "public_stories_status_idx": {
+ "name": "public_stories_status_idx",
+ "columns": [
+ "status"
+ ],
+ "isUnique": false
+ },
+ "public_stories_vault_idx": {
+ "name": "public_stories_vault_idx",
+ "columns": [
+ "vault_id"
+ ],
+ "isUnique": false
+ }
+ },
+ "foreignKeys": {
+ "public_stories_vault_id_vaults_id_fk": {
+ "name": "public_stories_vault_id_vaults_id_fk",
+ "tableFrom": "public_stories",
+ "tableTo": "vaults",
+ "columnsFrom": [
+ "vault_id"
+ ],
+ "columnsTo": [
+ "id"
+ ],
+ "onDelete": "cascade",
+ "onUpdate": "no action"
+ },
+ "public_stories_debt_id_debts_id_fk": {
+ "name": "public_stories_debt_id_debts_id_fk",
+ "tableFrom": "public_stories",
+ "tableTo": "debts",
+ "columnsFrom": [
+ "debt_id"
+ ],
+ "columnsTo": [
+ "id"
+ ],
+ "onDelete": "cascade",
+ "onUpdate": "no action"
+ }
+ },
+ "compositePrimaryKeys": {},
+ "uniqueConstraints": {},
+ "checkConstraints": {}
+ },
+ "story_encouragements": {
+ "name": "story_encouragements",
+ "columns": {
+ "id": {
+ "name": "id",
+ "type": "text",
+ "primaryKey": true,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "story_id": {
+ "name": "story_id",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "vault_id": {
+ "name": "vault_id",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "created_at": {
+ "name": "created_at",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": "CURRENT_TIMESTAMP"
+ }
+ },
+ "indexes": {
+ "story_encouragement_unique": {
+ "name": "story_encouragement_unique",
+ "columns": [
+ "story_id",
+ "vault_id"
+ ],
+ "isUnique": true
+ },
+ "story_encouragement_story_idx": {
+ "name": "story_encouragement_story_idx",
+ "columns": [
+ "story_id"
+ ],
+ "isUnique": false
+ }
+ },
+ "foreignKeys": {
+ "story_encouragements_story_id_public_stories_id_fk": {
+ "name": "story_encouragements_story_id_public_stories_id_fk",
+ "tableFrom": "story_encouragements",
+ "tableTo": "public_stories",
+ "columnsFrom": [
+ "story_id"
+ ],
+ "columnsTo": [
+ "id"
+ ],
+ "onDelete": "cascade",
+ "onUpdate": "no action"
+ },
+ "story_encouragements_vault_id_vaults_id_fk": {
+ "name": "story_encouragements_vault_id_vaults_id_fk",
+ "tableFrom": "story_encouragements",
+ "tableTo": "vaults",
+ "columnsFrom": [
+ "vault_id"
+ ],
+ "columnsTo": [
+ "id"
+ ],
+ "onDelete": "cascade",
+ "onUpdate": "no action"
+ }
+ },
+ "compositePrimaryKeys": {},
+ "uniqueConstraints": {},
+ "checkConstraints": {}
+ },
+ "story_reports": {
+ "name": "story_reports",
+ "columns": {
+ "id": {
+ "name": "id",
+ "type": "text",
+ "primaryKey": true,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "story_id": {
+ "name": "story_id",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "reporter_vault_id": {
+ "name": "reporter_vault_id",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "reason": {
+ "name": "reason",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "details": {
+ "name": "details",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": "''"
+ },
+ "status": {
+ "name": "status",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": "'open'"
+ },
+ "created_at": {
+ "name": "created_at",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": "CURRENT_TIMESTAMP"
+ },
+ "resolved_at": {
+ "name": "resolved_at",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": false,
+ "autoincrement": false
+ }
+ },
+ "indexes": {
+ "story_report_unique": {
+ "name": "story_report_unique",
+ "columns": [
+ "story_id",
+ "reporter_vault_id"
+ ],
+ "isUnique": true
+ },
+ "story_reports_status_idx": {
+ "name": "story_reports_status_idx",
+ "columns": [
+ "status"
+ ],
+ "isUnique": false
+ }
+ },
+ "foreignKeys": {
+ "story_reports_story_id_public_stories_id_fk": {
+ "name": "story_reports_story_id_public_stories_id_fk",
+ "tableFrom": "story_reports",
+ "tableTo": "public_stories",
+ "columnsFrom": [
+ "story_id"
+ ],
+ "columnsTo": [
+ "id"
+ ],
+ "onDelete": "cascade",
+ "onUpdate": "no action"
+ },
+ "story_reports_reporter_vault_id_vaults_id_fk": {
+ "name": "story_reports_reporter_vault_id_vaults_id_fk",
+ "tableFrom": "story_reports",
+ "tableTo": "vaults",
+ "columnsFrom": [
+ "reporter_vault_id"
+ ],
+ "columnsTo": [
+ "id"
+ ],
+ "onDelete": "cascade",
+ "onUpdate": "no action"
+ }
+ },
+ "compositePrimaryKeys": {},
+ "uniqueConstraints": {},
+ "checkConstraints": {}
+ },
+ "vaults": {
+ "name": "vaults",
+ "columns": {
+ "id": {
+ "name": "id",
+ "type": "text",
+ "primaryKey": true,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "recovery_hash": {
+ "name": "recovery_hash",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "alias": {
+ "name": "alias",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "region": {
+ "name": "region",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "pressure": {
+ "name": "pressure",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": "''"
+ },
+ "position_x": {
+ "name": "position_x",
+ "type": "real",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": 47
+ },
+ "position_y": {
+ "name": "position_y",
+ "type": "real",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": 63
+ },
+ "locale": {
+ "name": "locale",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": "'zh'"
+ },
+ "country_code": {
+ "name": "country_code",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": "''"
+ },
+ "country_name": {
+ "name": "country_name",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": "''"
+ },
+ "display_currency": {
+ "name": "display_currency",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": "'CNY'"
+ },
+ "monthly_income": {
+ "name": "monthly_income",
+ "type": "real",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": 0
+ },
+ "monthly_expenses": {
+ "name": "monthly_expenses",
+ "type": "real",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": 0
+ },
+ "discovery_consent": {
+ "name": "discovery_consent",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": false
+ },
+ "created_at": {
+ "name": "created_at",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": "CURRENT_TIMESTAMP"
+ },
+ "updated_at": {
+ "name": "updated_at",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": "CURRENT_TIMESTAMP"
+ }
+ },
+ "indexes": {
+ "vaults_recovery_hash_unique": {
+ "name": "vaults_recovery_hash_unique",
+ "columns": [
+ "recovery_hash"
+ ],
+ "isUnique": true
+ }
+ },
+ "foreignKeys": {},
+ "compositePrimaryKeys": {},
+ "uniqueConstraints": {},
+ "checkConstraints": {}
+ },
+ "world_category_candidates": {
+ "name": "world_category_candidates",
+ "columns": {
+ "id": {
+ "name": "id",
+ "type": "text",
+ "primaryKey": true,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "canonical_key": {
+ "name": "canonical_key",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "parent_kind": {
+ "name": "parent_kind",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": "'other'"
+ },
+ "name_zh": {
+ "name": "name_zh",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "name_en": {
+ "name": "name_en",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "description_zh": {
+ "name": "description_zh",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": "''"
+ },
+ "description_en": {
+ "name": "description_en",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": "''"
+ },
+ "status": {
+ "name": "status",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": "'candidate'"
+ },
+ "stage": {
+ "name": "stage",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": 0
+ },
+ "confidence": {
+ "name": "confidence",
+ "type": "real",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": 0
+ },
+ "unique_vaults": {
+ "name": "unique_vaults",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": 0
+ },
+ "region_count": {
+ "name": "region_count",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": 0
+ },
+ "mention_count": {
+ "name": "mention_count",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": 0
+ },
+ "emergence_score": {
+ "name": "emergence_score",
+ "type": "real",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": 0
+ },
+ "weight_profile_id": {
+ "name": "weight_profile_id",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": false,
+ "autoincrement": false
+ },
+ "merged_into_id": {
+ "name": "merged_into_id",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": false,
+ "autoincrement": false
+ },
+ "proposed_at": {
+ "name": "proposed_at",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": "CURRENT_TIMESTAMP"
+ },
+ "reviewed_at": {
+ "name": "reviewed_at",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": false,
+ "autoincrement": false
+ },
+ "published_at": {
+ "name": "published_at",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": false,
+ "autoincrement": false
+ },
+ "updated_at": {
+ "name": "updated_at",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": "CURRENT_TIMESTAMP"
+ }
+ },
+ "indexes": {
+ "world_category_candidates_canonical_key_unique": {
+ "name": "world_category_candidates_canonical_key_unique",
+ "columns": [
+ "canonical_key"
+ ],
+ "isUnique": true
+ },
+ "world_candidates_status_idx": {
+ "name": "world_candidates_status_idx",
+ "columns": [
+ "status"
+ ],
+ "isUnique": false
+ },
+ "world_candidates_score_idx": {
+ "name": "world_candidates_score_idx",
+ "columns": [
+ "emergence_score"
+ ],
+ "isUnique": false
+ }
+ },
+ "foreignKeys": {
+ "world_category_candidates_weight_profile_id_world_weight_profiles_id_fk": {
+ "name": "world_category_candidates_weight_profile_id_world_weight_profiles_id_fk",
+ "tableFrom": "world_category_candidates",
+ "tableTo": "world_weight_profiles",
+ "columnsFrom": [
+ "weight_profile_id"
+ ],
+ "columnsTo": [
+ "id"
+ ],
+ "onDelete": "no action",
+ "onUpdate": "no action"
+ }
+ },
+ "compositePrimaryKeys": {},
+ "uniqueConstraints": {},
+ "checkConstraints": {}
+ },
+ "world_growth_events": {
+ "name": "world_growth_events",
+ "columns": {
+ "id": {
+ "name": "id",
+ "type": "text",
+ "primaryKey": true,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "candidate_id": {
+ "name": "candidate_id",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "event_type": {
+ "name": "event_type",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "from_stage": {
+ "name": "from_stage",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": false,
+ "autoincrement": false
+ },
+ "to_stage": {
+ "name": "to_stage",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": false,
+ "autoincrement": false
+ },
+ "actor_type": {
+ "name": "actor_type",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": "'system'"
+ },
+ "weight_profile_id": {
+ "name": "weight_profile_id",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": false,
+ "autoincrement": false
+ },
+ "evidence_json": {
+ "name": "evidence_json",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": "'{}'"
+ },
+ "reason": {
+ "name": "reason",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": "''"
+ },
+ "created_at": {
+ "name": "created_at",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": "CURRENT_TIMESTAMP"
+ }
+ },
+ "indexes": {
+ "world_events_candidate_idx": {
+ "name": "world_events_candidate_idx",
+ "columns": [
+ "candidate_id"
+ ],
+ "isUnique": false
+ }
+ },
+ "foreignKeys": {
+ "world_growth_events_candidate_id_world_category_candidates_id_fk": {
+ "name": "world_growth_events_candidate_id_world_category_candidates_id_fk",
+ "tableFrom": "world_growth_events",
+ "tableTo": "world_category_candidates",
+ "columnsFrom": [
+ "candidate_id"
+ ],
+ "columnsTo": [
+ "id"
+ ],
+ "onDelete": "cascade",
+ "onUpdate": "no action"
+ },
+ "world_growth_events_weight_profile_id_world_weight_profiles_id_fk": {
+ "name": "world_growth_events_weight_profile_id_world_weight_profiles_id_fk",
+ "tableFrom": "world_growth_events",
+ "tableTo": "world_weight_profiles",
+ "columnsFrom": [
+ "weight_profile_id"
+ ],
+ "columnsTo": [
+ "id"
+ ],
+ "onDelete": "no action",
+ "onUpdate": "no action"
+ }
+ },
+ "compositePrimaryKeys": {},
+ "uniqueConstraints": {},
+ "checkConstraints": {}
+ },
+ "world_signal_assignments": {
+ "name": "world_signal_assignments",
+ "columns": {
+ "id": {
+ "name": "id",
+ "type": "text",
+ "primaryKey": true,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "vault_id": {
+ "name": "vault_id",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "debt_id": {
+ "name": "debt_id",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "candidate_id": {
+ "name": "candidate_id",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "confidence": {
+ "name": "confidence",
+ "type": "real",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "assignment_source": {
+ "name": "assignment_source",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": "'ai'"
+ },
+ "taxonomy_version": {
+ "name": "taxonomy_version",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": 1
+ },
+ "created_at": {
+ "name": "created_at",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": "CURRENT_TIMESTAMP"
+ },
+ "updated_at": {
+ "name": "updated_at",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": "CURRENT_TIMESTAMP"
+ }
+ },
+ "indexes": {
+ "world_signal_assignments_debt_id_unique": {
+ "name": "world_signal_assignments_debt_id_unique",
+ "columns": [
+ "debt_id"
+ ],
+ "isUnique": true
+ },
+ "world_signals_vault_idx": {
+ "name": "world_signals_vault_idx",
+ "columns": [
+ "vault_id"
+ ],
+ "isUnique": false
+ },
+ "world_signals_candidate_idx": {
+ "name": "world_signals_candidate_idx",
+ "columns": [
+ "candidate_id"
+ ],
+ "isUnique": false
+ }
+ },
+ "foreignKeys": {
+ "world_signal_assignments_vault_id_vaults_id_fk": {
+ "name": "world_signal_assignments_vault_id_vaults_id_fk",
+ "tableFrom": "world_signal_assignments",
+ "tableTo": "vaults",
+ "columnsFrom": [
+ "vault_id"
+ ],
+ "columnsTo": [
+ "id"
+ ],
+ "onDelete": "cascade",
+ "onUpdate": "no action"
+ },
+ "world_signal_assignments_debt_id_debts_id_fk": {
+ "name": "world_signal_assignments_debt_id_debts_id_fk",
+ "tableFrom": "world_signal_assignments",
+ "tableTo": "debts",
+ "columnsFrom": [
+ "debt_id"
+ ],
+ "columnsTo": [
+ "id"
+ ],
+ "onDelete": "cascade",
+ "onUpdate": "no action"
+ },
+ "world_signal_assignments_candidate_id_world_category_candidates_id_fk": {
+ "name": "world_signal_assignments_candidate_id_world_category_candidates_id_fk",
+ "tableFrom": "world_signal_assignments",
+ "tableTo": "world_category_candidates",
+ "columnsFrom": [
+ "candidate_id"
+ ],
+ "columnsTo": [
+ "id"
+ ],
+ "onDelete": "cascade",
+ "onUpdate": "no action"
+ }
+ },
+ "compositePrimaryKeys": {},
+ "uniqueConstraints": {},
+ "checkConstraints": {}
+ },
+ "world_weight_profiles": {
+ "name": "world_weight_profiles",
+ "columns": {
+ "id": {
+ "name": "id",
+ "type": "text",
+ "primaryKey": true,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "version": {
+ "name": "version",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "status": {
+ "name": "status",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": "'draft'"
+ },
+ "frequency_weight": {
+ "name": "frequency_weight",
+ "type": "real",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "growth_weight": {
+ "name": "growth_weight",
+ "type": "real",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "geography_weight": {
+ "name": "geography_weight",
+ "type": "real",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "recurrence_weight": {
+ "name": "recurrence_weight",
+ "type": "real",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "connection_weight": {
+ "name": "connection_weight",
+ "type": "real",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "quality_weight": {
+ "name": "quality_weight",
+ "type": "real",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "proposed_by": {
+ "name": "proposed_by",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": "'human'"
+ },
+ "model_ref": {
+ "name": "model_ref",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": false,
+ "autoincrement": false
+ },
+ "rationale": {
+ "name": "rationale",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": "''"
+ },
+ "created_at": {
+ "name": "created_at",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": "CURRENT_TIMESTAMP"
+ },
+ "activated_at": {
+ "name": "activated_at",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": false,
+ "autoincrement": false
+ }
+ },
+ "indexes": {
+ "world_weight_profiles_version_unique": {
+ "name": "world_weight_profiles_version_unique",
+ "columns": [
+ "version"
+ ],
+ "isUnique": true
+ }
+ },
+ "foreignKeys": {},
+ "compositePrimaryKeys": {},
+ "uniqueConstraints": {},
+ "checkConstraints": {}
+ }
+ },
+ "views": {},
+ "enums": {},
+ "_meta": {
+ "schemas": {},
+ "tables": {},
+ "columns": {}
+ },
+ "internal": {
+ "indexes": {}
+ }
+}
\ No newline at end of file
diff --git a/drizzle/meta/0010_snapshot.json b/drizzle/meta/0010_snapshot.json
new file mode 100644
index 0000000..9ad6a78
--- /dev/null
+++ b/drizzle/meta/0010_snapshot.json
@@ -0,0 +1,1793 @@
+{
+ "version": "6",
+ "dialect": "sqlite",
+ "id": "97cee09d-51af-4529-a4f4-24858566015c",
+ "prevId": "96353f86-7864-411e-96d8-495bde164d74",
+ "tables": {
+ "ai_daily_usage": {
+ "name": "ai_daily_usage",
+ "columns": {
+ "id": {
+ "name": "id",
+ "type": "text",
+ "primaryKey": true,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "vault_id": {
+ "name": "vault_id",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "usage_date": {
+ "name": "usage_date",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "request_count": {
+ "name": "request_count",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": 0
+ },
+ "input_tokens": {
+ "name": "input_tokens",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": 0
+ },
+ "output_tokens": {
+ "name": "output_tokens",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": 0
+ },
+ "updated_at": {
+ "name": "updated_at",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": "CURRENT_TIMESTAMP"
+ }
+ },
+ "indexes": {
+ "ai_daily_usage_vault_date_unique": {
+ "name": "ai_daily_usage_vault_date_unique",
+ "columns": [
+ "vault_id",
+ "usage_date"
+ ],
+ "isUnique": true
+ },
+ "ai_daily_usage_date_idx": {
+ "name": "ai_daily_usage_date_idx",
+ "columns": [
+ "usage_date"
+ ],
+ "isUnique": false
+ }
+ },
+ "foreignKeys": {
+ "ai_daily_usage_vault_id_vaults_id_fk": {
+ "name": "ai_daily_usage_vault_id_vaults_id_fk",
+ "tableFrom": "ai_daily_usage",
+ "tableTo": "vaults",
+ "columnsFrom": [
+ "vault_id"
+ ],
+ "columnsTo": [
+ "id"
+ ],
+ "onDelete": "cascade",
+ "onUpdate": "no action"
+ }
+ },
+ "compositePrimaryKeys": {},
+ "uniqueConstraints": {},
+ "checkConstraints": {}
+ },
+ "community_moderation_actions": {
+ "name": "community_moderation_actions",
+ "columns": {
+ "id": {
+ "name": "id",
+ "type": "text",
+ "primaryKey": true,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "story_id": {
+ "name": "story_id",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "actor_digest": {
+ "name": "actor_digest",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "action": {
+ "name": "action",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "from_status": {
+ "name": "from_status",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "to_status": {
+ "name": "to_status",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "note": {
+ "name": "note",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": "''"
+ },
+ "created_at": {
+ "name": "created_at",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": "CURRENT_TIMESTAMP"
+ }
+ },
+ "indexes": {
+ "community_moderation_story_idx": {
+ "name": "community_moderation_story_idx",
+ "columns": [
+ "story_id"
+ ],
+ "isUnique": false
+ },
+ "community_moderation_created_idx": {
+ "name": "community_moderation_created_idx",
+ "columns": [
+ "created_at"
+ ],
+ "isUnique": false
+ }
+ },
+ "foreignKeys": {
+ "community_moderation_actions_story_id_public_stories_id_fk": {
+ "name": "community_moderation_actions_story_id_public_stories_id_fk",
+ "tableFrom": "community_moderation_actions",
+ "tableTo": "public_stories",
+ "columnsFrom": [
+ "story_id"
+ ],
+ "columnsTo": [
+ "id"
+ ],
+ "onDelete": "cascade",
+ "onUpdate": "no action"
+ }
+ },
+ "compositePrimaryKeys": {},
+ "uniqueConstraints": {},
+ "checkConstraints": {}
+ },
+ "community_rate_limits": {
+ "name": "community_rate_limits",
+ "columns": {
+ "id": {
+ "name": "id",
+ "type": "text",
+ "primaryKey": true,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "vault_id": {
+ "name": "vault_id",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "action": {
+ "name": "action",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "window_key": {
+ "name": "window_key",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "count": {
+ "name": "count",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": 0
+ },
+ "updated_at": {
+ "name": "updated_at",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": "CURRENT_TIMESTAMP"
+ }
+ },
+ "indexes": {
+ "community_rate_vault_action_window_unique": {
+ "name": "community_rate_vault_action_window_unique",
+ "columns": [
+ "vault_id",
+ "action",
+ "window_key"
+ ],
+ "isUnique": true
+ },
+ "community_rate_window_idx": {
+ "name": "community_rate_window_idx",
+ "columns": [
+ "window_key"
+ ],
+ "isUnique": false
+ }
+ },
+ "foreignKeys": {
+ "community_rate_limits_vault_id_vaults_id_fk": {
+ "name": "community_rate_limits_vault_id_vaults_id_fk",
+ "tableFrom": "community_rate_limits",
+ "tableTo": "vaults",
+ "columnsFrom": [
+ "vault_id"
+ ],
+ "columnsTo": [
+ "id"
+ ],
+ "onDelete": "cascade",
+ "onUpdate": "no action"
+ }
+ },
+ "compositePrimaryKeys": {},
+ "uniqueConstraints": {},
+ "checkConstraints": {}
+ },
+ "debts": {
+ "name": "debts",
+ "columns": {
+ "id": {
+ "name": "id",
+ "type": "text",
+ "primaryKey": true,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "vault_id": {
+ "name": "vault_id",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "kind": {
+ "name": "kind",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "custom_label": {
+ "name": "custom_label",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": false,
+ "autoincrement": false
+ },
+ "currency": {
+ "name": "currency",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "original": {
+ "name": "original",
+ "type": "real",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "balance": {
+ "name": "balance",
+ "type": "real",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "monthly": {
+ "name": "monthly",
+ "type": "real",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "apr": {
+ "name": "apr",
+ "type": "real",
+ "primaryKey": false,
+ "notNull": false,
+ "autoincrement": false
+ },
+ "minimum_payment": {
+ "name": "minimum_payment",
+ "type": "real",
+ "primaryKey": false,
+ "notNull": false,
+ "autoincrement": false
+ },
+ "payment_status": {
+ "name": "payment_status",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": "'unknown'"
+ },
+ "remaining_months": {
+ "name": "remaining_months",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": false,
+ "autoincrement": false
+ },
+ "due_day": {
+ "name": "due_day",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "method": {
+ "name": "method",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "sharing_mode": {
+ "name": "sharing_mode",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": "'private'"
+ },
+ "last_paid_at": {
+ "name": "last_paid_at",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": false,
+ "autoincrement": false
+ },
+ "payments": {
+ "name": "payments",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": 0
+ },
+ "created_at": {
+ "name": "created_at",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": "CURRENT_TIMESTAMP"
+ },
+ "updated_at": {
+ "name": "updated_at",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": "CURRENT_TIMESTAMP"
+ }
+ },
+ "indexes": {
+ "debts_vault_id_idx": {
+ "name": "debts_vault_id_idx",
+ "columns": [
+ "vault_id"
+ ],
+ "isUnique": false
+ }
+ },
+ "foreignKeys": {
+ "debts_vault_id_vaults_id_fk": {
+ "name": "debts_vault_id_vaults_id_fk",
+ "tableFrom": "debts",
+ "tableTo": "vaults",
+ "columnsFrom": [
+ "vault_id"
+ ],
+ "columnsTo": [
+ "id"
+ ],
+ "onDelete": "cascade",
+ "onUpdate": "no action"
+ }
+ },
+ "compositePrimaryKeys": {},
+ "uniqueConstraints": {},
+ "checkConstraints": {}
+ },
+ "lucky_income_claims": {
+ "name": "lucky_income_claims",
+ "columns": {
+ "id": {
+ "name": "id",
+ "type": "text",
+ "primaryKey": true,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "vault_id": {
+ "name": "vault_id",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "event_date": {
+ "name": "event_date",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "created_at": {
+ "name": "created_at",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": "CURRENT_TIMESTAMP"
+ }
+ },
+ "indexes": {
+ "lucky_income_vault_day_unique": {
+ "name": "lucky_income_vault_day_unique",
+ "columns": [
+ "vault_id",
+ "event_date"
+ ],
+ "isUnique": true
+ }
+ },
+ "foreignKeys": {
+ "lucky_income_claims_vault_id_vaults_id_fk": {
+ "name": "lucky_income_claims_vault_id_vaults_id_fk",
+ "tableFrom": "lucky_income_claims",
+ "tableTo": "vaults",
+ "columnsFrom": [
+ "vault_id"
+ ],
+ "columnsTo": [
+ "id"
+ ],
+ "onDelete": "cascade",
+ "onUpdate": "no action"
+ }
+ },
+ "compositePrimaryKeys": {},
+ "uniqueConstraints": {},
+ "checkConstraints": {}
+ },
+ "payment_records": {
+ "name": "payment_records",
+ "columns": {
+ "id": {
+ "name": "id",
+ "type": "text",
+ "primaryKey": true,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "vault_id": {
+ "name": "vault_id",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "debt_id": {
+ "name": "debt_id",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "scheduled_date": {
+ "name": "scheduled_date",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": false,
+ "autoincrement": false
+ },
+ "confirmed_at": {
+ "name": "confirmed_at",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "event_date": {
+ "name": "event_date",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": false,
+ "autoincrement": false
+ },
+ "cash_payment": {
+ "name": "cash_payment",
+ "type": "real",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "new_balance": {
+ "name": "new_balance",
+ "type": "real",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "source": {
+ "name": "source",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": "'self_report'"
+ },
+ "income_type": {
+ "name": "income_type",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": false,
+ "autoincrement": false
+ },
+ "created_at": {
+ "name": "created_at",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": "CURRENT_TIMESTAMP"
+ }
+ },
+ "indexes": {
+ "payments_vault_id_idx": {
+ "name": "payments_vault_id_idx",
+ "columns": [
+ "vault_id"
+ ],
+ "isUnique": false
+ },
+ "payments_debt_id_idx": {
+ "name": "payments_debt_id_idx",
+ "columns": [
+ "debt_id"
+ ],
+ "isUnique": false
+ }
+ },
+ "foreignKeys": {
+ "payment_records_vault_id_vaults_id_fk": {
+ "name": "payment_records_vault_id_vaults_id_fk",
+ "tableFrom": "payment_records",
+ "tableTo": "vaults",
+ "columnsFrom": [
+ "vault_id"
+ ],
+ "columnsTo": [
+ "id"
+ ],
+ "onDelete": "cascade",
+ "onUpdate": "no action"
+ },
+ "payment_records_debt_id_debts_id_fk": {
+ "name": "payment_records_debt_id_debts_id_fk",
+ "tableFrom": "payment_records",
+ "tableTo": "debts",
+ "columnsFrom": [
+ "debt_id"
+ ],
+ "columnsTo": [
+ "id"
+ ],
+ "onDelete": "cascade",
+ "onUpdate": "no action"
+ }
+ },
+ "compositePrimaryKeys": {},
+ "uniqueConstraints": {},
+ "checkConstraints": {}
+ },
+ "policy_acceptances": {
+ "name": "policy_acceptances",
+ "columns": {
+ "id": {
+ "name": "id",
+ "type": "text",
+ "primaryKey": true,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "vault_id": {
+ "name": "vault_id",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "policy_key": {
+ "name": "policy_key",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "policy_version": {
+ "name": "policy_version",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "accepted_at": {
+ "name": "accepted_at",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": "CURRENT_TIMESTAMP"
+ }
+ },
+ "indexes": {
+ "policy_acceptance_vault_key_version_unique": {
+ "name": "policy_acceptance_vault_key_version_unique",
+ "columns": [
+ "vault_id",
+ "policy_key",
+ "policy_version"
+ ],
+ "isUnique": true
+ },
+ "policy_acceptance_vault_idx": {
+ "name": "policy_acceptance_vault_idx",
+ "columns": [
+ "vault_id"
+ ],
+ "isUnique": false
+ }
+ },
+ "foreignKeys": {
+ "policy_acceptances_vault_id_vaults_id_fk": {
+ "name": "policy_acceptances_vault_id_vaults_id_fk",
+ "tableFrom": "policy_acceptances",
+ "tableTo": "vaults",
+ "columnsFrom": [
+ "vault_id"
+ ],
+ "columnsTo": [
+ "id"
+ ],
+ "onDelete": "cascade",
+ "onUpdate": "no action"
+ }
+ },
+ "compositePrimaryKeys": {},
+ "uniqueConstraints": {},
+ "checkConstraints": {}
+ },
+ "public_stories": {
+ "name": "public_stories",
+ "columns": {
+ "id": {
+ "name": "id",
+ "type": "text",
+ "primaryKey": true,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "vault_id": {
+ "name": "vault_id",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "debt_id": {
+ "name": "debt_id",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "anonymous_name": {
+ "name": "anonymous_name",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "country_code": {
+ "name": "country_code",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": "''"
+ },
+ "debt_kind": {
+ "name": "debt_kind",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "amount_band": {
+ "name": "amount_band",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "currency": {
+ "name": "currency",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "repayment_approach": {
+ "name": "repayment_approach",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": "'other'"
+ },
+ "story_text": {
+ "name": "story_text",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "status": {
+ "name": "status",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": "'pending'"
+ },
+ "created_at": {
+ "name": "created_at",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": "CURRENT_TIMESTAMP"
+ },
+ "updated_at": {
+ "name": "updated_at",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": "CURRENT_TIMESTAMP"
+ }
+ },
+ "indexes": {
+ "public_stories_status_idx": {
+ "name": "public_stories_status_idx",
+ "columns": [
+ "status"
+ ],
+ "isUnique": false
+ },
+ "public_stories_vault_idx": {
+ "name": "public_stories_vault_idx",
+ "columns": [
+ "vault_id"
+ ],
+ "isUnique": false
+ }
+ },
+ "foreignKeys": {
+ "public_stories_vault_id_vaults_id_fk": {
+ "name": "public_stories_vault_id_vaults_id_fk",
+ "tableFrom": "public_stories",
+ "tableTo": "vaults",
+ "columnsFrom": [
+ "vault_id"
+ ],
+ "columnsTo": [
+ "id"
+ ],
+ "onDelete": "cascade",
+ "onUpdate": "no action"
+ },
+ "public_stories_debt_id_debts_id_fk": {
+ "name": "public_stories_debt_id_debts_id_fk",
+ "tableFrom": "public_stories",
+ "tableTo": "debts",
+ "columnsFrom": [
+ "debt_id"
+ ],
+ "columnsTo": [
+ "id"
+ ],
+ "onDelete": "cascade",
+ "onUpdate": "no action"
+ }
+ },
+ "compositePrimaryKeys": {},
+ "uniqueConstraints": {},
+ "checkConstraints": {}
+ },
+ "story_encouragements": {
+ "name": "story_encouragements",
+ "columns": {
+ "id": {
+ "name": "id",
+ "type": "text",
+ "primaryKey": true,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "story_id": {
+ "name": "story_id",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "vault_id": {
+ "name": "vault_id",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "created_at": {
+ "name": "created_at",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": "CURRENT_TIMESTAMP"
+ }
+ },
+ "indexes": {
+ "story_encouragement_unique": {
+ "name": "story_encouragement_unique",
+ "columns": [
+ "story_id",
+ "vault_id"
+ ],
+ "isUnique": true
+ },
+ "story_encouragement_story_idx": {
+ "name": "story_encouragement_story_idx",
+ "columns": [
+ "story_id"
+ ],
+ "isUnique": false
+ }
+ },
+ "foreignKeys": {
+ "story_encouragements_story_id_public_stories_id_fk": {
+ "name": "story_encouragements_story_id_public_stories_id_fk",
+ "tableFrom": "story_encouragements",
+ "tableTo": "public_stories",
+ "columnsFrom": [
+ "story_id"
+ ],
+ "columnsTo": [
+ "id"
+ ],
+ "onDelete": "cascade",
+ "onUpdate": "no action"
+ },
+ "story_encouragements_vault_id_vaults_id_fk": {
+ "name": "story_encouragements_vault_id_vaults_id_fk",
+ "tableFrom": "story_encouragements",
+ "tableTo": "vaults",
+ "columnsFrom": [
+ "vault_id"
+ ],
+ "columnsTo": [
+ "id"
+ ],
+ "onDelete": "cascade",
+ "onUpdate": "no action"
+ }
+ },
+ "compositePrimaryKeys": {},
+ "uniqueConstraints": {},
+ "checkConstraints": {}
+ },
+ "story_reports": {
+ "name": "story_reports",
+ "columns": {
+ "id": {
+ "name": "id",
+ "type": "text",
+ "primaryKey": true,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "story_id": {
+ "name": "story_id",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "reporter_vault_id": {
+ "name": "reporter_vault_id",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "reason": {
+ "name": "reason",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "details": {
+ "name": "details",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": "''"
+ },
+ "status": {
+ "name": "status",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": "'open'"
+ },
+ "created_at": {
+ "name": "created_at",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": "CURRENT_TIMESTAMP"
+ },
+ "resolved_at": {
+ "name": "resolved_at",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": false,
+ "autoincrement": false
+ }
+ },
+ "indexes": {
+ "story_report_unique": {
+ "name": "story_report_unique",
+ "columns": [
+ "story_id",
+ "reporter_vault_id"
+ ],
+ "isUnique": true
+ },
+ "story_reports_status_idx": {
+ "name": "story_reports_status_idx",
+ "columns": [
+ "status"
+ ],
+ "isUnique": false
+ }
+ },
+ "foreignKeys": {
+ "story_reports_story_id_public_stories_id_fk": {
+ "name": "story_reports_story_id_public_stories_id_fk",
+ "tableFrom": "story_reports",
+ "tableTo": "public_stories",
+ "columnsFrom": [
+ "story_id"
+ ],
+ "columnsTo": [
+ "id"
+ ],
+ "onDelete": "cascade",
+ "onUpdate": "no action"
+ },
+ "story_reports_reporter_vault_id_vaults_id_fk": {
+ "name": "story_reports_reporter_vault_id_vaults_id_fk",
+ "tableFrom": "story_reports",
+ "tableTo": "vaults",
+ "columnsFrom": [
+ "reporter_vault_id"
+ ],
+ "columnsTo": [
+ "id"
+ ],
+ "onDelete": "cascade",
+ "onUpdate": "no action"
+ }
+ },
+ "compositePrimaryKeys": {},
+ "uniqueConstraints": {},
+ "checkConstraints": {}
+ },
+ "vaults": {
+ "name": "vaults",
+ "columns": {
+ "id": {
+ "name": "id",
+ "type": "text",
+ "primaryKey": true,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "recovery_hash": {
+ "name": "recovery_hash",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "alias": {
+ "name": "alias",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "region": {
+ "name": "region",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "pressure": {
+ "name": "pressure",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": "''"
+ },
+ "position_x": {
+ "name": "position_x",
+ "type": "real",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": 47
+ },
+ "position_y": {
+ "name": "position_y",
+ "type": "real",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": 63
+ },
+ "locale": {
+ "name": "locale",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": "'zh'"
+ },
+ "country_code": {
+ "name": "country_code",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": "''"
+ },
+ "country_name": {
+ "name": "country_name",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": "''"
+ },
+ "display_currency": {
+ "name": "display_currency",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": "'CNY'"
+ },
+ "monthly_income": {
+ "name": "monthly_income",
+ "type": "real",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": 0
+ },
+ "monthly_expenses": {
+ "name": "monthly_expenses",
+ "type": "real",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": 0
+ },
+ "discovery_consent": {
+ "name": "discovery_consent",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": false
+ },
+ "created_at": {
+ "name": "created_at",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": "CURRENT_TIMESTAMP"
+ },
+ "updated_at": {
+ "name": "updated_at",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": "CURRENT_TIMESTAMP"
+ }
+ },
+ "indexes": {
+ "vaults_recovery_hash_unique": {
+ "name": "vaults_recovery_hash_unique",
+ "columns": [
+ "recovery_hash"
+ ],
+ "isUnique": true
+ }
+ },
+ "foreignKeys": {},
+ "compositePrimaryKeys": {},
+ "uniqueConstraints": {},
+ "checkConstraints": {}
+ },
+ "world_category_candidates": {
+ "name": "world_category_candidates",
+ "columns": {
+ "id": {
+ "name": "id",
+ "type": "text",
+ "primaryKey": true,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "canonical_key": {
+ "name": "canonical_key",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "parent_kind": {
+ "name": "parent_kind",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": "'other'"
+ },
+ "name_zh": {
+ "name": "name_zh",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "name_en": {
+ "name": "name_en",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "description_zh": {
+ "name": "description_zh",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": "''"
+ },
+ "description_en": {
+ "name": "description_en",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": "''"
+ },
+ "status": {
+ "name": "status",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": "'candidate'"
+ },
+ "stage": {
+ "name": "stage",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": 0
+ },
+ "confidence": {
+ "name": "confidence",
+ "type": "real",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": 0
+ },
+ "unique_vaults": {
+ "name": "unique_vaults",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": 0
+ },
+ "region_count": {
+ "name": "region_count",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": 0
+ },
+ "mention_count": {
+ "name": "mention_count",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": 0
+ },
+ "emergence_score": {
+ "name": "emergence_score",
+ "type": "real",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": 0
+ },
+ "weight_profile_id": {
+ "name": "weight_profile_id",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": false,
+ "autoincrement": false
+ },
+ "merged_into_id": {
+ "name": "merged_into_id",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": false,
+ "autoincrement": false
+ },
+ "proposed_at": {
+ "name": "proposed_at",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": "CURRENT_TIMESTAMP"
+ },
+ "reviewed_at": {
+ "name": "reviewed_at",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": false,
+ "autoincrement": false
+ },
+ "published_at": {
+ "name": "published_at",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": false,
+ "autoincrement": false
+ },
+ "updated_at": {
+ "name": "updated_at",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": "CURRENT_TIMESTAMP"
+ }
+ },
+ "indexes": {
+ "world_category_candidates_canonical_key_unique": {
+ "name": "world_category_candidates_canonical_key_unique",
+ "columns": [
+ "canonical_key"
+ ],
+ "isUnique": true
+ },
+ "world_candidates_status_idx": {
+ "name": "world_candidates_status_idx",
+ "columns": [
+ "status"
+ ],
+ "isUnique": false
+ },
+ "world_candidates_score_idx": {
+ "name": "world_candidates_score_idx",
+ "columns": [
+ "emergence_score"
+ ],
+ "isUnique": false
+ }
+ },
+ "foreignKeys": {
+ "world_category_candidates_weight_profile_id_world_weight_profiles_id_fk": {
+ "name": "world_category_candidates_weight_profile_id_world_weight_profiles_id_fk",
+ "tableFrom": "world_category_candidates",
+ "tableTo": "world_weight_profiles",
+ "columnsFrom": [
+ "weight_profile_id"
+ ],
+ "columnsTo": [
+ "id"
+ ],
+ "onDelete": "no action",
+ "onUpdate": "no action"
+ }
+ },
+ "compositePrimaryKeys": {},
+ "uniqueConstraints": {},
+ "checkConstraints": {}
+ },
+ "world_growth_events": {
+ "name": "world_growth_events",
+ "columns": {
+ "id": {
+ "name": "id",
+ "type": "text",
+ "primaryKey": true,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "candidate_id": {
+ "name": "candidate_id",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "event_type": {
+ "name": "event_type",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "from_stage": {
+ "name": "from_stage",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": false,
+ "autoincrement": false
+ },
+ "to_stage": {
+ "name": "to_stage",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": false,
+ "autoincrement": false
+ },
+ "actor_type": {
+ "name": "actor_type",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": "'system'"
+ },
+ "weight_profile_id": {
+ "name": "weight_profile_id",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": false,
+ "autoincrement": false
+ },
+ "evidence_json": {
+ "name": "evidence_json",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": "'{}'"
+ },
+ "reason": {
+ "name": "reason",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": "''"
+ },
+ "created_at": {
+ "name": "created_at",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": "CURRENT_TIMESTAMP"
+ }
+ },
+ "indexes": {
+ "world_events_candidate_idx": {
+ "name": "world_events_candidate_idx",
+ "columns": [
+ "candidate_id"
+ ],
+ "isUnique": false
+ }
+ },
+ "foreignKeys": {
+ "world_growth_events_candidate_id_world_category_candidates_id_fk": {
+ "name": "world_growth_events_candidate_id_world_category_candidates_id_fk",
+ "tableFrom": "world_growth_events",
+ "tableTo": "world_category_candidates",
+ "columnsFrom": [
+ "candidate_id"
+ ],
+ "columnsTo": [
+ "id"
+ ],
+ "onDelete": "cascade",
+ "onUpdate": "no action"
+ },
+ "world_growth_events_weight_profile_id_world_weight_profiles_id_fk": {
+ "name": "world_growth_events_weight_profile_id_world_weight_profiles_id_fk",
+ "tableFrom": "world_growth_events",
+ "tableTo": "world_weight_profiles",
+ "columnsFrom": [
+ "weight_profile_id"
+ ],
+ "columnsTo": [
+ "id"
+ ],
+ "onDelete": "no action",
+ "onUpdate": "no action"
+ }
+ },
+ "compositePrimaryKeys": {},
+ "uniqueConstraints": {},
+ "checkConstraints": {}
+ },
+ "world_signal_assignments": {
+ "name": "world_signal_assignments",
+ "columns": {
+ "id": {
+ "name": "id",
+ "type": "text",
+ "primaryKey": true,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "vault_id": {
+ "name": "vault_id",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "debt_id": {
+ "name": "debt_id",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "candidate_id": {
+ "name": "candidate_id",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "confidence": {
+ "name": "confidence",
+ "type": "real",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "assignment_source": {
+ "name": "assignment_source",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": "'ai'"
+ },
+ "taxonomy_version": {
+ "name": "taxonomy_version",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": 1
+ },
+ "created_at": {
+ "name": "created_at",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": "CURRENT_TIMESTAMP"
+ },
+ "updated_at": {
+ "name": "updated_at",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": "CURRENT_TIMESTAMP"
+ }
+ },
+ "indexes": {
+ "world_signal_assignments_debt_id_unique": {
+ "name": "world_signal_assignments_debt_id_unique",
+ "columns": [
+ "debt_id"
+ ],
+ "isUnique": true
+ },
+ "world_signals_vault_idx": {
+ "name": "world_signals_vault_idx",
+ "columns": [
+ "vault_id"
+ ],
+ "isUnique": false
+ },
+ "world_signals_candidate_idx": {
+ "name": "world_signals_candidate_idx",
+ "columns": [
+ "candidate_id"
+ ],
+ "isUnique": false
+ }
+ },
+ "foreignKeys": {
+ "world_signal_assignments_vault_id_vaults_id_fk": {
+ "name": "world_signal_assignments_vault_id_vaults_id_fk",
+ "tableFrom": "world_signal_assignments",
+ "tableTo": "vaults",
+ "columnsFrom": [
+ "vault_id"
+ ],
+ "columnsTo": [
+ "id"
+ ],
+ "onDelete": "cascade",
+ "onUpdate": "no action"
+ },
+ "world_signal_assignments_debt_id_debts_id_fk": {
+ "name": "world_signal_assignments_debt_id_debts_id_fk",
+ "tableFrom": "world_signal_assignments",
+ "tableTo": "debts",
+ "columnsFrom": [
+ "debt_id"
+ ],
+ "columnsTo": [
+ "id"
+ ],
+ "onDelete": "cascade",
+ "onUpdate": "no action"
+ },
+ "world_signal_assignments_candidate_id_world_category_candidates_id_fk": {
+ "name": "world_signal_assignments_candidate_id_world_category_candidates_id_fk",
+ "tableFrom": "world_signal_assignments",
+ "tableTo": "world_category_candidates",
+ "columnsFrom": [
+ "candidate_id"
+ ],
+ "columnsTo": [
+ "id"
+ ],
+ "onDelete": "cascade",
+ "onUpdate": "no action"
+ }
+ },
+ "compositePrimaryKeys": {},
+ "uniqueConstraints": {},
+ "checkConstraints": {}
+ },
+ "world_weight_profiles": {
+ "name": "world_weight_profiles",
+ "columns": {
+ "id": {
+ "name": "id",
+ "type": "text",
+ "primaryKey": true,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "version": {
+ "name": "version",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "status": {
+ "name": "status",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": "'draft'"
+ },
+ "frequency_weight": {
+ "name": "frequency_weight",
+ "type": "real",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "growth_weight": {
+ "name": "growth_weight",
+ "type": "real",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "geography_weight": {
+ "name": "geography_weight",
+ "type": "real",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "recurrence_weight": {
+ "name": "recurrence_weight",
+ "type": "real",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "connection_weight": {
+ "name": "connection_weight",
+ "type": "real",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "quality_weight": {
+ "name": "quality_weight",
+ "type": "real",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "proposed_by": {
+ "name": "proposed_by",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": "'human'"
+ },
+ "model_ref": {
+ "name": "model_ref",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": false,
+ "autoincrement": false
+ },
+ "rationale": {
+ "name": "rationale",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": "''"
+ },
+ "created_at": {
+ "name": "created_at",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": "CURRENT_TIMESTAMP"
+ },
+ "activated_at": {
+ "name": "activated_at",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": false,
+ "autoincrement": false
+ }
+ },
+ "indexes": {
+ "world_weight_profiles_version_unique": {
+ "name": "world_weight_profiles_version_unique",
+ "columns": [
+ "version"
+ ],
+ "isUnique": true
+ }
+ },
+ "foreignKeys": {},
+ "compositePrimaryKeys": {},
+ "uniqueConstraints": {},
+ "checkConstraints": {}
+ }
+ },
+ "views": {},
+ "enums": {},
+ "_meta": {
+ "schemas": {},
+ "tables": {},
+ "columns": {}
+ },
+ "internal": {
+ "indexes": {}
+ }
+}
\ No newline at end of file
diff --git a/drizzle/meta/0011_snapshot.json b/drizzle/meta/0011_snapshot.json
new file mode 100644
index 0000000..81cfc84
--- /dev/null
+++ b/drizzle/meta/0011_snapshot.json
@@ -0,0 +1,2052 @@
+{
+ "version": "6",
+ "dialect": "sqlite",
+ "id": "509820b1-4cc7-44d1-b954-607901c213d2",
+ "prevId": "97cee09d-51af-4529-a4f4-24858566015c",
+ "tables": {
+ "ai_daily_usage": {
+ "name": "ai_daily_usage",
+ "columns": {
+ "id": {
+ "name": "id",
+ "type": "text",
+ "primaryKey": true,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "vault_id": {
+ "name": "vault_id",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "usage_date": {
+ "name": "usage_date",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "request_count": {
+ "name": "request_count",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": 0
+ },
+ "input_tokens": {
+ "name": "input_tokens",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": 0
+ },
+ "output_tokens": {
+ "name": "output_tokens",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": 0
+ },
+ "updated_at": {
+ "name": "updated_at",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": "CURRENT_TIMESTAMP"
+ }
+ },
+ "indexes": {
+ "ai_daily_usage_vault_date_unique": {
+ "name": "ai_daily_usage_vault_date_unique",
+ "columns": [
+ "vault_id",
+ "usage_date"
+ ],
+ "isUnique": true
+ },
+ "ai_daily_usage_date_idx": {
+ "name": "ai_daily_usage_date_idx",
+ "columns": [
+ "usage_date"
+ ],
+ "isUnique": false
+ }
+ },
+ "foreignKeys": {
+ "ai_daily_usage_vault_id_vaults_id_fk": {
+ "name": "ai_daily_usage_vault_id_vaults_id_fk",
+ "tableFrom": "ai_daily_usage",
+ "tableTo": "vaults",
+ "columnsFrom": [
+ "vault_id"
+ ],
+ "columnsTo": [
+ "id"
+ ],
+ "onDelete": "cascade",
+ "onUpdate": "no action"
+ }
+ },
+ "compositePrimaryKeys": {},
+ "uniqueConstraints": {},
+ "checkConstraints": {}
+ },
+ "beta_enrollments": {
+ "name": "beta_enrollments",
+ "columns": {
+ "id": {
+ "name": "id",
+ "type": "text",
+ "primaryKey": true,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "vault_id": {
+ "name": "vault_id",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "invite_digest": {
+ "name": "invite_digest",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "consent_version": {
+ "name": "consent_version",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "created_at": {
+ "name": "created_at",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": "CURRENT_TIMESTAMP"
+ }
+ },
+ "indexes": {
+ "beta_enrollments_vault_id_unique": {
+ "name": "beta_enrollments_vault_id_unique",
+ "columns": [
+ "vault_id"
+ ],
+ "isUnique": true
+ },
+ "beta_enrollments_created_idx": {
+ "name": "beta_enrollments_created_idx",
+ "columns": [
+ "created_at"
+ ],
+ "isUnique": false
+ }
+ },
+ "foreignKeys": {
+ "beta_enrollments_vault_id_vaults_id_fk": {
+ "name": "beta_enrollments_vault_id_vaults_id_fk",
+ "tableFrom": "beta_enrollments",
+ "tableTo": "vaults",
+ "columnsFrom": [
+ "vault_id"
+ ],
+ "columnsTo": [
+ "id"
+ ],
+ "onDelete": "cascade",
+ "onUpdate": "no action"
+ }
+ },
+ "compositePrimaryKeys": {},
+ "uniqueConstraints": {},
+ "checkConstraints": {}
+ },
+ "beta_feedback": {
+ "name": "beta_feedback",
+ "columns": {
+ "id": {
+ "name": "id",
+ "type": "text",
+ "primaryKey": true,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "vault_id": {
+ "name": "vault_id",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "category": {
+ "name": "category",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "rating": {
+ "name": "rating",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "message": {
+ "name": "message",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "page_path": {
+ "name": "page_path",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": "'/'"
+ },
+ "status": {
+ "name": "status",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": "'open'"
+ },
+ "created_at": {
+ "name": "created_at",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": "CURRENT_TIMESTAMP"
+ },
+ "resolved_at": {
+ "name": "resolved_at",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": false,
+ "autoincrement": false
+ }
+ },
+ "indexes": {
+ "beta_feedback_vault_idx": {
+ "name": "beta_feedback_vault_idx",
+ "columns": [
+ "vault_id"
+ ],
+ "isUnique": false
+ },
+ "beta_feedback_status_idx": {
+ "name": "beta_feedback_status_idx",
+ "columns": [
+ "status"
+ ],
+ "isUnique": false
+ }
+ },
+ "foreignKeys": {
+ "beta_feedback_vault_id_vaults_id_fk": {
+ "name": "beta_feedback_vault_id_vaults_id_fk",
+ "tableFrom": "beta_feedback",
+ "tableTo": "vaults",
+ "columnsFrom": [
+ "vault_id"
+ ],
+ "columnsTo": [
+ "id"
+ ],
+ "onDelete": "cascade",
+ "onUpdate": "no action"
+ }
+ },
+ "compositePrimaryKeys": {},
+ "uniqueConstraints": {},
+ "checkConstraints": {}
+ },
+ "beta_invite_counters": {
+ "name": "beta_invite_counters",
+ "columns": {
+ "invite_digest": {
+ "name": "invite_digest",
+ "type": "text",
+ "primaryKey": true,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "uses": {
+ "name": "uses",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": 0
+ },
+ "max_uses": {
+ "name": "max_uses",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "updated_at": {
+ "name": "updated_at",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": "CURRENT_TIMESTAMP"
+ }
+ },
+ "indexes": {},
+ "foreignKeys": {},
+ "compositePrimaryKeys": {},
+ "uniqueConstraints": {},
+ "checkConstraints": {}
+ },
+ "beta_runtime_settings": {
+ "name": "beta_runtime_settings",
+ "columns": {
+ "id": {
+ "name": "id",
+ "type": "text",
+ "primaryKey": true,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "signups_enabled": {
+ "name": "signups_enabled",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "updated_by_digest": {
+ "name": "updated_by_digest",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": false,
+ "autoincrement": false
+ },
+ "updated_at": {
+ "name": "updated_at",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": "CURRENT_TIMESTAMP"
+ }
+ },
+ "indexes": {},
+ "foreignKeys": {},
+ "compositePrimaryKeys": {},
+ "uniqueConstraints": {},
+ "checkConstraints": {}
+ },
+ "community_moderation_actions": {
+ "name": "community_moderation_actions",
+ "columns": {
+ "id": {
+ "name": "id",
+ "type": "text",
+ "primaryKey": true,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "story_id": {
+ "name": "story_id",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "actor_digest": {
+ "name": "actor_digest",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "action": {
+ "name": "action",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "from_status": {
+ "name": "from_status",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "to_status": {
+ "name": "to_status",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "note": {
+ "name": "note",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": "''"
+ },
+ "created_at": {
+ "name": "created_at",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": "CURRENT_TIMESTAMP"
+ }
+ },
+ "indexes": {
+ "community_moderation_story_idx": {
+ "name": "community_moderation_story_idx",
+ "columns": [
+ "story_id"
+ ],
+ "isUnique": false
+ },
+ "community_moderation_created_idx": {
+ "name": "community_moderation_created_idx",
+ "columns": [
+ "created_at"
+ ],
+ "isUnique": false
+ }
+ },
+ "foreignKeys": {
+ "community_moderation_actions_story_id_public_stories_id_fk": {
+ "name": "community_moderation_actions_story_id_public_stories_id_fk",
+ "tableFrom": "community_moderation_actions",
+ "tableTo": "public_stories",
+ "columnsFrom": [
+ "story_id"
+ ],
+ "columnsTo": [
+ "id"
+ ],
+ "onDelete": "cascade",
+ "onUpdate": "no action"
+ }
+ },
+ "compositePrimaryKeys": {},
+ "uniqueConstraints": {},
+ "checkConstraints": {}
+ },
+ "community_rate_limits": {
+ "name": "community_rate_limits",
+ "columns": {
+ "id": {
+ "name": "id",
+ "type": "text",
+ "primaryKey": true,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "vault_id": {
+ "name": "vault_id",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "action": {
+ "name": "action",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "window_key": {
+ "name": "window_key",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "count": {
+ "name": "count",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": 0
+ },
+ "updated_at": {
+ "name": "updated_at",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": "CURRENT_TIMESTAMP"
+ }
+ },
+ "indexes": {
+ "community_rate_vault_action_window_unique": {
+ "name": "community_rate_vault_action_window_unique",
+ "columns": [
+ "vault_id",
+ "action",
+ "window_key"
+ ],
+ "isUnique": true
+ },
+ "community_rate_window_idx": {
+ "name": "community_rate_window_idx",
+ "columns": [
+ "window_key"
+ ],
+ "isUnique": false
+ }
+ },
+ "foreignKeys": {
+ "community_rate_limits_vault_id_vaults_id_fk": {
+ "name": "community_rate_limits_vault_id_vaults_id_fk",
+ "tableFrom": "community_rate_limits",
+ "tableTo": "vaults",
+ "columnsFrom": [
+ "vault_id"
+ ],
+ "columnsTo": [
+ "id"
+ ],
+ "onDelete": "cascade",
+ "onUpdate": "no action"
+ }
+ },
+ "compositePrimaryKeys": {},
+ "uniqueConstraints": {},
+ "checkConstraints": {}
+ },
+ "debts": {
+ "name": "debts",
+ "columns": {
+ "id": {
+ "name": "id",
+ "type": "text",
+ "primaryKey": true,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "vault_id": {
+ "name": "vault_id",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "kind": {
+ "name": "kind",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "custom_label": {
+ "name": "custom_label",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": false,
+ "autoincrement": false
+ },
+ "currency": {
+ "name": "currency",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "original": {
+ "name": "original",
+ "type": "real",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "balance": {
+ "name": "balance",
+ "type": "real",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "monthly": {
+ "name": "monthly",
+ "type": "real",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "apr": {
+ "name": "apr",
+ "type": "real",
+ "primaryKey": false,
+ "notNull": false,
+ "autoincrement": false
+ },
+ "minimum_payment": {
+ "name": "minimum_payment",
+ "type": "real",
+ "primaryKey": false,
+ "notNull": false,
+ "autoincrement": false
+ },
+ "payment_status": {
+ "name": "payment_status",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": "'unknown'"
+ },
+ "remaining_months": {
+ "name": "remaining_months",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": false,
+ "autoincrement": false
+ },
+ "due_day": {
+ "name": "due_day",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "method": {
+ "name": "method",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "sharing_mode": {
+ "name": "sharing_mode",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": "'private'"
+ },
+ "last_paid_at": {
+ "name": "last_paid_at",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": false,
+ "autoincrement": false
+ },
+ "payments": {
+ "name": "payments",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": 0
+ },
+ "created_at": {
+ "name": "created_at",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": "CURRENT_TIMESTAMP"
+ },
+ "updated_at": {
+ "name": "updated_at",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": "CURRENT_TIMESTAMP"
+ }
+ },
+ "indexes": {
+ "debts_vault_id_idx": {
+ "name": "debts_vault_id_idx",
+ "columns": [
+ "vault_id"
+ ],
+ "isUnique": false
+ }
+ },
+ "foreignKeys": {
+ "debts_vault_id_vaults_id_fk": {
+ "name": "debts_vault_id_vaults_id_fk",
+ "tableFrom": "debts",
+ "tableTo": "vaults",
+ "columnsFrom": [
+ "vault_id"
+ ],
+ "columnsTo": [
+ "id"
+ ],
+ "onDelete": "cascade",
+ "onUpdate": "no action"
+ }
+ },
+ "compositePrimaryKeys": {},
+ "uniqueConstraints": {},
+ "checkConstraints": {}
+ },
+ "lucky_income_claims": {
+ "name": "lucky_income_claims",
+ "columns": {
+ "id": {
+ "name": "id",
+ "type": "text",
+ "primaryKey": true,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "vault_id": {
+ "name": "vault_id",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "event_date": {
+ "name": "event_date",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "created_at": {
+ "name": "created_at",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": "CURRENT_TIMESTAMP"
+ }
+ },
+ "indexes": {
+ "lucky_income_vault_day_unique": {
+ "name": "lucky_income_vault_day_unique",
+ "columns": [
+ "vault_id",
+ "event_date"
+ ],
+ "isUnique": true
+ }
+ },
+ "foreignKeys": {
+ "lucky_income_claims_vault_id_vaults_id_fk": {
+ "name": "lucky_income_claims_vault_id_vaults_id_fk",
+ "tableFrom": "lucky_income_claims",
+ "tableTo": "vaults",
+ "columnsFrom": [
+ "vault_id"
+ ],
+ "columnsTo": [
+ "id"
+ ],
+ "onDelete": "cascade",
+ "onUpdate": "no action"
+ }
+ },
+ "compositePrimaryKeys": {},
+ "uniqueConstraints": {},
+ "checkConstraints": {}
+ },
+ "payment_records": {
+ "name": "payment_records",
+ "columns": {
+ "id": {
+ "name": "id",
+ "type": "text",
+ "primaryKey": true,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "vault_id": {
+ "name": "vault_id",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "debt_id": {
+ "name": "debt_id",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "scheduled_date": {
+ "name": "scheduled_date",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": false,
+ "autoincrement": false
+ },
+ "confirmed_at": {
+ "name": "confirmed_at",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "event_date": {
+ "name": "event_date",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": false,
+ "autoincrement": false
+ },
+ "cash_payment": {
+ "name": "cash_payment",
+ "type": "real",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "new_balance": {
+ "name": "new_balance",
+ "type": "real",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "source": {
+ "name": "source",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": "'self_report'"
+ },
+ "income_type": {
+ "name": "income_type",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": false,
+ "autoincrement": false
+ },
+ "created_at": {
+ "name": "created_at",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": "CURRENT_TIMESTAMP"
+ }
+ },
+ "indexes": {
+ "payments_vault_id_idx": {
+ "name": "payments_vault_id_idx",
+ "columns": [
+ "vault_id"
+ ],
+ "isUnique": false
+ },
+ "payments_debt_id_idx": {
+ "name": "payments_debt_id_idx",
+ "columns": [
+ "debt_id"
+ ],
+ "isUnique": false
+ }
+ },
+ "foreignKeys": {
+ "payment_records_vault_id_vaults_id_fk": {
+ "name": "payment_records_vault_id_vaults_id_fk",
+ "tableFrom": "payment_records",
+ "tableTo": "vaults",
+ "columnsFrom": [
+ "vault_id"
+ ],
+ "columnsTo": [
+ "id"
+ ],
+ "onDelete": "cascade",
+ "onUpdate": "no action"
+ },
+ "payment_records_debt_id_debts_id_fk": {
+ "name": "payment_records_debt_id_debts_id_fk",
+ "tableFrom": "payment_records",
+ "tableTo": "debts",
+ "columnsFrom": [
+ "debt_id"
+ ],
+ "columnsTo": [
+ "id"
+ ],
+ "onDelete": "cascade",
+ "onUpdate": "no action"
+ }
+ },
+ "compositePrimaryKeys": {},
+ "uniqueConstraints": {},
+ "checkConstraints": {}
+ },
+ "policy_acceptances": {
+ "name": "policy_acceptances",
+ "columns": {
+ "id": {
+ "name": "id",
+ "type": "text",
+ "primaryKey": true,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "vault_id": {
+ "name": "vault_id",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "policy_key": {
+ "name": "policy_key",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "policy_version": {
+ "name": "policy_version",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "accepted_at": {
+ "name": "accepted_at",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": "CURRENT_TIMESTAMP"
+ }
+ },
+ "indexes": {
+ "policy_acceptance_vault_key_version_unique": {
+ "name": "policy_acceptance_vault_key_version_unique",
+ "columns": [
+ "vault_id",
+ "policy_key",
+ "policy_version"
+ ],
+ "isUnique": true
+ },
+ "policy_acceptance_vault_idx": {
+ "name": "policy_acceptance_vault_idx",
+ "columns": [
+ "vault_id"
+ ],
+ "isUnique": false
+ }
+ },
+ "foreignKeys": {
+ "policy_acceptances_vault_id_vaults_id_fk": {
+ "name": "policy_acceptances_vault_id_vaults_id_fk",
+ "tableFrom": "policy_acceptances",
+ "tableTo": "vaults",
+ "columnsFrom": [
+ "vault_id"
+ ],
+ "columnsTo": [
+ "id"
+ ],
+ "onDelete": "cascade",
+ "onUpdate": "no action"
+ }
+ },
+ "compositePrimaryKeys": {},
+ "uniqueConstraints": {},
+ "checkConstraints": {}
+ },
+ "public_stories": {
+ "name": "public_stories",
+ "columns": {
+ "id": {
+ "name": "id",
+ "type": "text",
+ "primaryKey": true,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "vault_id": {
+ "name": "vault_id",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "debt_id": {
+ "name": "debt_id",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "anonymous_name": {
+ "name": "anonymous_name",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "country_code": {
+ "name": "country_code",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": "''"
+ },
+ "debt_kind": {
+ "name": "debt_kind",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "amount_band": {
+ "name": "amount_band",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "currency": {
+ "name": "currency",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "repayment_approach": {
+ "name": "repayment_approach",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": "'other'"
+ },
+ "story_text": {
+ "name": "story_text",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "status": {
+ "name": "status",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": "'pending'"
+ },
+ "created_at": {
+ "name": "created_at",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": "CURRENT_TIMESTAMP"
+ },
+ "updated_at": {
+ "name": "updated_at",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": "CURRENT_TIMESTAMP"
+ }
+ },
+ "indexes": {
+ "public_stories_status_idx": {
+ "name": "public_stories_status_idx",
+ "columns": [
+ "status"
+ ],
+ "isUnique": false
+ },
+ "public_stories_vault_idx": {
+ "name": "public_stories_vault_idx",
+ "columns": [
+ "vault_id"
+ ],
+ "isUnique": false
+ }
+ },
+ "foreignKeys": {
+ "public_stories_vault_id_vaults_id_fk": {
+ "name": "public_stories_vault_id_vaults_id_fk",
+ "tableFrom": "public_stories",
+ "tableTo": "vaults",
+ "columnsFrom": [
+ "vault_id"
+ ],
+ "columnsTo": [
+ "id"
+ ],
+ "onDelete": "cascade",
+ "onUpdate": "no action"
+ },
+ "public_stories_debt_id_debts_id_fk": {
+ "name": "public_stories_debt_id_debts_id_fk",
+ "tableFrom": "public_stories",
+ "tableTo": "debts",
+ "columnsFrom": [
+ "debt_id"
+ ],
+ "columnsTo": [
+ "id"
+ ],
+ "onDelete": "cascade",
+ "onUpdate": "no action"
+ }
+ },
+ "compositePrimaryKeys": {},
+ "uniqueConstraints": {},
+ "checkConstraints": {}
+ },
+ "story_encouragements": {
+ "name": "story_encouragements",
+ "columns": {
+ "id": {
+ "name": "id",
+ "type": "text",
+ "primaryKey": true,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "story_id": {
+ "name": "story_id",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "vault_id": {
+ "name": "vault_id",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "created_at": {
+ "name": "created_at",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": "CURRENT_TIMESTAMP"
+ }
+ },
+ "indexes": {
+ "story_encouragement_unique": {
+ "name": "story_encouragement_unique",
+ "columns": [
+ "story_id",
+ "vault_id"
+ ],
+ "isUnique": true
+ },
+ "story_encouragement_story_idx": {
+ "name": "story_encouragement_story_idx",
+ "columns": [
+ "story_id"
+ ],
+ "isUnique": false
+ }
+ },
+ "foreignKeys": {
+ "story_encouragements_story_id_public_stories_id_fk": {
+ "name": "story_encouragements_story_id_public_stories_id_fk",
+ "tableFrom": "story_encouragements",
+ "tableTo": "public_stories",
+ "columnsFrom": [
+ "story_id"
+ ],
+ "columnsTo": [
+ "id"
+ ],
+ "onDelete": "cascade",
+ "onUpdate": "no action"
+ },
+ "story_encouragements_vault_id_vaults_id_fk": {
+ "name": "story_encouragements_vault_id_vaults_id_fk",
+ "tableFrom": "story_encouragements",
+ "tableTo": "vaults",
+ "columnsFrom": [
+ "vault_id"
+ ],
+ "columnsTo": [
+ "id"
+ ],
+ "onDelete": "cascade",
+ "onUpdate": "no action"
+ }
+ },
+ "compositePrimaryKeys": {},
+ "uniqueConstraints": {},
+ "checkConstraints": {}
+ },
+ "story_reports": {
+ "name": "story_reports",
+ "columns": {
+ "id": {
+ "name": "id",
+ "type": "text",
+ "primaryKey": true,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "story_id": {
+ "name": "story_id",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "reporter_vault_id": {
+ "name": "reporter_vault_id",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "reason": {
+ "name": "reason",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "details": {
+ "name": "details",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": "''"
+ },
+ "status": {
+ "name": "status",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": "'open'"
+ },
+ "created_at": {
+ "name": "created_at",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": "CURRENT_TIMESTAMP"
+ },
+ "resolved_at": {
+ "name": "resolved_at",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": false,
+ "autoincrement": false
+ }
+ },
+ "indexes": {
+ "story_report_unique": {
+ "name": "story_report_unique",
+ "columns": [
+ "story_id",
+ "reporter_vault_id"
+ ],
+ "isUnique": true
+ },
+ "story_reports_status_idx": {
+ "name": "story_reports_status_idx",
+ "columns": [
+ "status"
+ ],
+ "isUnique": false
+ }
+ },
+ "foreignKeys": {
+ "story_reports_story_id_public_stories_id_fk": {
+ "name": "story_reports_story_id_public_stories_id_fk",
+ "tableFrom": "story_reports",
+ "tableTo": "public_stories",
+ "columnsFrom": [
+ "story_id"
+ ],
+ "columnsTo": [
+ "id"
+ ],
+ "onDelete": "cascade",
+ "onUpdate": "no action"
+ },
+ "story_reports_reporter_vault_id_vaults_id_fk": {
+ "name": "story_reports_reporter_vault_id_vaults_id_fk",
+ "tableFrom": "story_reports",
+ "tableTo": "vaults",
+ "columnsFrom": [
+ "reporter_vault_id"
+ ],
+ "columnsTo": [
+ "id"
+ ],
+ "onDelete": "cascade",
+ "onUpdate": "no action"
+ }
+ },
+ "compositePrimaryKeys": {},
+ "uniqueConstraints": {},
+ "checkConstraints": {}
+ },
+ "vaults": {
+ "name": "vaults",
+ "columns": {
+ "id": {
+ "name": "id",
+ "type": "text",
+ "primaryKey": true,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "recovery_hash": {
+ "name": "recovery_hash",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "alias": {
+ "name": "alias",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "region": {
+ "name": "region",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "pressure": {
+ "name": "pressure",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": "''"
+ },
+ "position_x": {
+ "name": "position_x",
+ "type": "real",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": 47
+ },
+ "position_y": {
+ "name": "position_y",
+ "type": "real",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": 63
+ },
+ "locale": {
+ "name": "locale",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": "'zh'"
+ },
+ "country_code": {
+ "name": "country_code",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": "''"
+ },
+ "country_name": {
+ "name": "country_name",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": "''"
+ },
+ "display_currency": {
+ "name": "display_currency",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": "'CNY'"
+ },
+ "monthly_income": {
+ "name": "monthly_income",
+ "type": "real",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": 0
+ },
+ "monthly_expenses": {
+ "name": "monthly_expenses",
+ "type": "real",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": 0
+ },
+ "discovery_consent": {
+ "name": "discovery_consent",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": false
+ },
+ "created_at": {
+ "name": "created_at",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": "CURRENT_TIMESTAMP"
+ },
+ "updated_at": {
+ "name": "updated_at",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": "CURRENT_TIMESTAMP"
+ }
+ },
+ "indexes": {
+ "vaults_recovery_hash_unique": {
+ "name": "vaults_recovery_hash_unique",
+ "columns": [
+ "recovery_hash"
+ ],
+ "isUnique": true
+ }
+ },
+ "foreignKeys": {},
+ "compositePrimaryKeys": {},
+ "uniqueConstraints": {},
+ "checkConstraints": {}
+ },
+ "world_category_candidates": {
+ "name": "world_category_candidates",
+ "columns": {
+ "id": {
+ "name": "id",
+ "type": "text",
+ "primaryKey": true,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "canonical_key": {
+ "name": "canonical_key",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "parent_kind": {
+ "name": "parent_kind",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": "'other'"
+ },
+ "name_zh": {
+ "name": "name_zh",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "name_en": {
+ "name": "name_en",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "description_zh": {
+ "name": "description_zh",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": "''"
+ },
+ "description_en": {
+ "name": "description_en",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": "''"
+ },
+ "status": {
+ "name": "status",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": "'candidate'"
+ },
+ "stage": {
+ "name": "stage",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": 0
+ },
+ "confidence": {
+ "name": "confidence",
+ "type": "real",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": 0
+ },
+ "unique_vaults": {
+ "name": "unique_vaults",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": 0
+ },
+ "region_count": {
+ "name": "region_count",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": 0
+ },
+ "mention_count": {
+ "name": "mention_count",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": 0
+ },
+ "emergence_score": {
+ "name": "emergence_score",
+ "type": "real",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": 0
+ },
+ "weight_profile_id": {
+ "name": "weight_profile_id",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": false,
+ "autoincrement": false
+ },
+ "merged_into_id": {
+ "name": "merged_into_id",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": false,
+ "autoincrement": false
+ },
+ "proposed_at": {
+ "name": "proposed_at",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": "CURRENT_TIMESTAMP"
+ },
+ "reviewed_at": {
+ "name": "reviewed_at",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": false,
+ "autoincrement": false
+ },
+ "published_at": {
+ "name": "published_at",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": false,
+ "autoincrement": false
+ },
+ "updated_at": {
+ "name": "updated_at",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": "CURRENT_TIMESTAMP"
+ }
+ },
+ "indexes": {
+ "world_category_candidates_canonical_key_unique": {
+ "name": "world_category_candidates_canonical_key_unique",
+ "columns": [
+ "canonical_key"
+ ],
+ "isUnique": true
+ },
+ "world_candidates_status_idx": {
+ "name": "world_candidates_status_idx",
+ "columns": [
+ "status"
+ ],
+ "isUnique": false
+ },
+ "world_candidates_score_idx": {
+ "name": "world_candidates_score_idx",
+ "columns": [
+ "emergence_score"
+ ],
+ "isUnique": false
+ }
+ },
+ "foreignKeys": {
+ "world_category_candidates_weight_profile_id_world_weight_profiles_id_fk": {
+ "name": "world_category_candidates_weight_profile_id_world_weight_profiles_id_fk",
+ "tableFrom": "world_category_candidates",
+ "tableTo": "world_weight_profiles",
+ "columnsFrom": [
+ "weight_profile_id"
+ ],
+ "columnsTo": [
+ "id"
+ ],
+ "onDelete": "no action",
+ "onUpdate": "no action"
+ }
+ },
+ "compositePrimaryKeys": {},
+ "uniqueConstraints": {},
+ "checkConstraints": {}
+ },
+ "world_growth_events": {
+ "name": "world_growth_events",
+ "columns": {
+ "id": {
+ "name": "id",
+ "type": "text",
+ "primaryKey": true,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "candidate_id": {
+ "name": "candidate_id",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "event_type": {
+ "name": "event_type",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "from_stage": {
+ "name": "from_stage",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": false,
+ "autoincrement": false
+ },
+ "to_stage": {
+ "name": "to_stage",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": false,
+ "autoincrement": false
+ },
+ "actor_type": {
+ "name": "actor_type",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": "'system'"
+ },
+ "weight_profile_id": {
+ "name": "weight_profile_id",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": false,
+ "autoincrement": false
+ },
+ "evidence_json": {
+ "name": "evidence_json",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": "'{}'"
+ },
+ "reason": {
+ "name": "reason",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": "''"
+ },
+ "created_at": {
+ "name": "created_at",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": "CURRENT_TIMESTAMP"
+ }
+ },
+ "indexes": {
+ "world_events_candidate_idx": {
+ "name": "world_events_candidate_idx",
+ "columns": [
+ "candidate_id"
+ ],
+ "isUnique": false
+ }
+ },
+ "foreignKeys": {
+ "world_growth_events_candidate_id_world_category_candidates_id_fk": {
+ "name": "world_growth_events_candidate_id_world_category_candidates_id_fk",
+ "tableFrom": "world_growth_events",
+ "tableTo": "world_category_candidates",
+ "columnsFrom": [
+ "candidate_id"
+ ],
+ "columnsTo": [
+ "id"
+ ],
+ "onDelete": "cascade",
+ "onUpdate": "no action"
+ },
+ "world_growth_events_weight_profile_id_world_weight_profiles_id_fk": {
+ "name": "world_growth_events_weight_profile_id_world_weight_profiles_id_fk",
+ "tableFrom": "world_growth_events",
+ "tableTo": "world_weight_profiles",
+ "columnsFrom": [
+ "weight_profile_id"
+ ],
+ "columnsTo": [
+ "id"
+ ],
+ "onDelete": "no action",
+ "onUpdate": "no action"
+ }
+ },
+ "compositePrimaryKeys": {},
+ "uniqueConstraints": {},
+ "checkConstraints": {}
+ },
+ "world_signal_assignments": {
+ "name": "world_signal_assignments",
+ "columns": {
+ "id": {
+ "name": "id",
+ "type": "text",
+ "primaryKey": true,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "vault_id": {
+ "name": "vault_id",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "debt_id": {
+ "name": "debt_id",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "candidate_id": {
+ "name": "candidate_id",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "confidence": {
+ "name": "confidence",
+ "type": "real",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "assignment_source": {
+ "name": "assignment_source",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": "'ai'"
+ },
+ "taxonomy_version": {
+ "name": "taxonomy_version",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": 1
+ },
+ "created_at": {
+ "name": "created_at",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": "CURRENT_TIMESTAMP"
+ },
+ "updated_at": {
+ "name": "updated_at",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": "CURRENT_TIMESTAMP"
+ }
+ },
+ "indexes": {
+ "world_signal_assignments_debt_id_unique": {
+ "name": "world_signal_assignments_debt_id_unique",
+ "columns": [
+ "debt_id"
+ ],
+ "isUnique": true
+ },
+ "world_signals_vault_idx": {
+ "name": "world_signals_vault_idx",
+ "columns": [
+ "vault_id"
+ ],
+ "isUnique": false
+ },
+ "world_signals_candidate_idx": {
+ "name": "world_signals_candidate_idx",
+ "columns": [
+ "candidate_id"
+ ],
+ "isUnique": false
+ }
+ },
+ "foreignKeys": {
+ "world_signal_assignments_vault_id_vaults_id_fk": {
+ "name": "world_signal_assignments_vault_id_vaults_id_fk",
+ "tableFrom": "world_signal_assignments",
+ "tableTo": "vaults",
+ "columnsFrom": [
+ "vault_id"
+ ],
+ "columnsTo": [
+ "id"
+ ],
+ "onDelete": "cascade",
+ "onUpdate": "no action"
+ },
+ "world_signal_assignments_debt_id_debts_id_fk": {
+ "name": "world_signal_assignments_debt_id_debts_id_fk",
+ "tableFrom": "world_signal_assignments",
+ "tableTo": "debts",
+ "columnsFrom": [
+ "debt_id"
+ ],
+ "columnsTo": [
+ "id"
+ ],
+ "onDelete": "cascade",
+ "onUpdate": "no action"
+ },
+ "world_signal_assignments_candidate_id_world_category_candidates_id_fk": {
+ "name": "world_signal_assignments_candidate_id_world_category_candidates_id_fk",
+ "tableFrom": "world_signal_assignments",
+ "tableTo": "world_category_candidates",
+ "columnsFrom": [
+ "candidate_id"
+ ],
+ "columnsTo": [
+ "id"
+ ],
+ "onDelete": "cascade",
+ "onUpdate": "no action"
+ }
+ },
+ "compositePrimaryKeys": {},
+ "uniqueConstraints": {},
+ "checkConstraints": {}
+ },
+ "world_weight_profiles": {
+ "name": "world_weight_profiles",
+ "columns": {
+ "id": {
+ "name": "id",
+ "type": "text",
+ "primaryKey": true,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "version": {
+ "name": "version",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "status": {
+ "name": "status",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": "'draft'"
+ },
+ "frequency_weight": {
+ "name": "frequency_weight",
+ "type": "real",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "growth_weight": {
+ "name": "growth_weight",
+ "type": "real",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "geography_weight": {
+ "name": "geography_weight",
+ "type": "real",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "recurrence_weight": {
+ "name": "recurrence_weight",
+ "type": "real",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "connection_weight": {
+ "name": "connection_weight",
+ "type": "real",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "quality_weight": {
+ "name": "quality_weight",
+ "type": "real",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "proposed_by": {
+ "name": "proposed_by",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": "'human'"
+ },
+ "model_ref": {
+ "name": "model_ref",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": false,
+ "autoincrement": false
+ },
+ "rationale": {
+ "name": "rationale",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": "''"
+ },
+ "created_at": {
+ "name": "created_at",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": "CURRENT_TIMESTAMP"
+ },
+ "activated_at": {
+ "name": "activated_at",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": false,
+ "autoincrement": false
+ }
+ },
+ "indexes": {
+ "world_weight_profiles_version_unique": {
+ "name": "world_weight_profiles_version_unique",
+ "columns": [
+ "version"
+ ],
+ "isUnique": true
+ }
+ },
+ "foreignKeys": {},
+ "compositePrimaryKeys": {},
+ "uniqueConstraints": {},
+ "checkConstraints": {}
+ }
+ },
+ "views": {},
+ "enums": {},
+ "_meta": {
+ "schemas": {},
+ "tables": {},
+ "columns": {}
+ },
+ "internal": {
+ "indexes": {}
+ }
+}
\ No newline at end of file
diff --git a/drizzle/meta/0012_snapshot.json b/drizzle/meta/0012_snapshot.json
new file mode 100644
index 0000000..a084f87
--- /dev/null
+++ b/drizzle/meta/0012_snapshot.json
@@ -0,0 +1,2446 @@
+{
+ "version": "6",
+ "dialect": "sqlite",
+ "id": "6dc4ae81-0c8d-4705-ba16-fd1e434e718c",
+ "prevId": "509820b1-4cc7-44d1-b954-607901c213d2",
+ "tables": {
+ "account_auth_limits": {
+ "name": "account_auth_limits",
+ "columns": {
+ "limit_key": {
+ "name": "limit_key",
+ "type": "text",
+ "primaryKey": true,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "action": {
+ "name": "action",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "window_key": {
+ "name": "window_key",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "attempts": {
+ "name": "attempts",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": 0
+ },
+ "updated_at": {
+ "name": "updated_at",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": "CURRENT_TIMESTAMP"
+ }
+ },
+ "indexes": {
+ "account_auth_limits_window_idx": {
+ "name": "account_auth_limits_window_idx",
+ "columns": [
+ "window_key"
+ ],
+ "isUnique": false
+ }
+ },
+ "foreignKeys": {},
+ "compositePrimaryKeys": {},
+ "uniqueConstraints": {},
+ "checkConstraints": {}
+ },
+ "account_sessions": {
+ "name": "account_sessions",
+ "columns": {
+ "id": {
+ "name": "id",
+ "type": "text",
+ "primaryKey": true,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "account_id": {
+ "name": "account_id",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "token_hash": {
+ "name": "token_hash",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "expires_at": {
+ "name": "expires_at",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "created_at": {
+ "name": "created_at",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": "CURRENT_TIMESTAMP"
+ },
+ "last_seen_at": {
+ "name": "last_seen_at",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": "CURRENT_TIMESTAMP"
+ }
+ },
+ "indexes": {
+ "account_sessions_token_hash_unique": {
+ "name": "account_sessions_token_hash_unique",
+ "columns": [
+ "token_hash"
+ ],
+ "isUnique": true
+ },
+ "account_sessions_account_idx": {
+ "name": "account_sessions_account_idx",
+ "columns": [
+ "account_id"
+ ],
+ "isUnique": false
+ },
+ "account_sessions_expires_idx": {
+ "name": "account_sessions_expires_idx",
+ "columns": [
+ "expires_at"
+ ],
+ "isUnique": false
+ }
+ },
+ "foreignKeys": {
+ "account_sessions_account_id_accounts_id_fk": {
+ "name": "account_sessions_account_id_accounts_id_fk",
+ "tableFrom": "account_sessions",
+ "tableTo": "accounts",
+ "columnsFrom": [
+ "account_id"
+ ],
+ "columnsTo": [
+ "id"
+ ],
+ "onDelete": "cascade",
+ "onUpdate": "no action"
+ }
+ },
+ "compositePrimaryKeys": {},
+ "uniqueConstraints": {},
+ "checkConstraints": {}
+ },
+ "account_vaults": {
+ "name": "account_vaults",
+ "columns": {
+ "account_id": {
+ "name": "account_id",
+ "type": "text",
+ "primaryKey": true,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "vault_id": {
+ "name": "vault_id",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "linked_at": {
+ "name": "linked_at",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": "CURRENT_TIMESTAMP"
+ }
+ },
+ "indexes": {
+ "account_vaults_vault_id_unique": {
+ "name": "account_vaults_vault_id_unique",
+ "columns": [
+ "vault_id"
+ ],
+ "isUnique": true
+ },
+ "account_vaults_vault_idx": {
+ "name": "account_vaults_vault_idx",
+ "columns": [
+ "vault_id"
+ ],
+ "isUnique": false
+ }
+ },
+ "foreignKeys": {
+ "account_vaults_account_id_accounts_id_fk": {
+ "name": "account_vaults_account_id_accounts_id_fk",
+ "tableFrom": "account_vaults",
+ "tableTo": "accounts",
+ "columnsFrom": [
+ "account_id"
+ ],
+ "columnsTo": [
+ "id"
+ ],
+ "onDelete": "cascade",
+ "onUpdate": "no action"
+ },
+ "account_vaults_vault_id_vaults_id_fk": {
+ "name": "account_vaults_vault_id_vaults_id_fk",
+ "tableFrom": "account_vaults",
+ "tableTo": "vaults",
+ "columnsFrom": [
+ "vault_id"
+ ],
+ "columnsTo": [
+ "id"
+ ],
+ "onDelete": "cascade",
+ "onUpdate": "no action"
+ }
+ },
+ "compositePrimaryKeys": {},
+ "uniqueConstraints": {},
+ "checkConstraints": {}
+ },
+ "accounts": {
+ "name": "accounts",
+ "columns": {
+ "id": {
+ "name": "id",
+ "type": "text",
+ "primaryKey": true,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "user_code": {
+ "name": "user_code",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "username": {
+ "name": "username",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "username_normalized": {
+ "name": "username_normalized",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "password_hash": {
+ "name": "password_hash",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "password_salt": {
+ "name": "password_salt",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "password_iterations": {
+ "name": "password_iterations",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "status": {
+ "name": "status",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": "'active'"
+ },
+ "created_at": {
+ "name": "created_at",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": "CURRENT_TIMESTAMP"
+ },
+ "updated_at": {
+ "name": "updated_at",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": "CURRENT_TIMESTAMP"
+ },
+ "last_login_at": {
+ "name": "last_login_at",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": false,
+ "autoincrement": false
+ },
+ "last_seen_at": {
+ "name": "last_seen_at",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": false,
+ "autoincrement": false
+ }
+ },
+ "indexes": {
+ "accounts_user_code_unique": {
+ "name": "accounts_user_code_unique",
+ "columns": [
+ "user_code"
+ ],
+ "isUnique": true
+ },
+ "accounts_username_normalized_unique": {
+ "name": "accounts_username_normalized_unique",
+ "columns": [
+ "username_normalized"
+ ],
+ "isUnique": true
+ },
+ "accounts_created_idx": {
+ "name": "accounts_created_idx",
+ "columns": [
+ "created_at"
+ ],
+ "isUnique": false
+ }
+ },
+ "foreignKeys": {},
+ "compositePrimaryKeys": {},
+ "uniqueConstraints": {},
+ "checkConstraints": {}
+ },
+ "ai_daily_usage": {
+ "name": "ai_daily_usage",
+ "columns": {
+ "id": {
+ "name": "id",
+ "type": "text",
+ "primaryKey": true,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "vault_id": {
+ "name": "vault_id",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "usage_date": {
+ "name": "usage_date",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "request_count": {
+ "name": "request_count",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": 0
+ },
+ "input_tokens": {
+ "name": "input_tokens",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": 0
+ },
+ "output_tokens": {
+ "name": "output_tokens",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": 0
+ },
+ "updated_at": {
+ "name": "updated_at",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": "CURRENT_TIMESTAMP"
+ }
+ },
+ "indexes": {
+ "ai_daily_usage_vault_date_unique": {
+ "name": "ai_daily_usage_vault_date_unique",
+ "columns": [
+ "vault_id",
+ "usage_date"
+ ],
+ "isUnique": true
+ },
+ "ai_daily_usage_date_idx": {
+ "name": "ai_daily_usage_date_idx",
+ "columns": [
+ "usage_date"
+ ],
+ "isUnique": false
+ }
+ },
+ "foreignKeys": {
+ "ai_daily_usage_vault_id_vaults_id_fk": {
+ "name": "ai_daily_usage_vault_id_vaults_id_fk",
+ "tableFrom": "ai_daily_usage",
+ "tableTo": "vaults",
+ "columnsFrom": [
+ "vault_id"
+ ],
+ "columnsTo": [
+ "id"
+ ],
+ "onDelete": "cascade",
+ "onUpdate": "no action"
+ }
+ },
+ "compositePrimaryKeys": {},
+ "uniqueConstraints": {},
+ "checkConstraints": {}
+ },
+ "beta_enrollments": {
+ "name": "beta_enrollments",
+ "columns": {
+ "id": {
+ "name": "id",
+ "type": "text",
+ "primaryKey": true,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "vault_id": {
+ "name": "vault_id",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "invite_digest": {
+ "name": "invite_digest",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "consent_version": {
+ "name": "consent_version",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "created_at": {
+ "name": "created_at",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": "CURRENT_TIMESTAMP"
+ }
+ },
+ "indexes": {
+ "beta_enrollments_vault_id_unique": {
+ "name": "beta_enrollments_vault_id_unique",
+ "columns": [
+ "vault_id"
+ ],
+ "isUnique": true
+ },
+ "beta_enrollments_created_idx": {
+ "name": "beta_enrollments_created_idx",
+ "columns": [
+ "created_at"
+ ],
+ "isUnique": false
+ }
+ },
+ "foreignKeys": {
+ "beta_enrollments_vault_id_vaults_id_fk": {
+ "name": "beta_enrollments_vault_id_vaults_id_fk",
+ "tableFrom": "beta_enrollments",
+ "tableTo": "vaults",
+ "columnsFrom": [
+ "vault_id"
+ ],
+ "columnsTo": [
+ "id"
+ ],
+ "onDelete": "cascade",
+ "onUpdate": "no action"
+ }
+ },
+ "compositePrimaryKeys": {},
+ "uniqueConstraints": {},
+ "checkConstraints": {}
+ },
+ "beta_feedback": {
+ "name": "beta_feedback",
+ "columns": {
+ "id": {
+ "name": "id",
+ "type": "text",
+ "primaryKey": true,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "vault_id": {
+ "name": "vault_id",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "category": {
+ "name": "category",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "rating": {
+ "name": "rating",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "message": {
+ "name": "message",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "page_path": {
+ "name": "page_path",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": "'/'"
+ },
+ "status": {
+ "name": "status",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": "'open'"
+ },
+ "created_at": {
+ "name": "created_at",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": "CURRENT_TIMESTAMP"
+ },
+ "resolved_at": {
+ "name": "resolved_at",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": false,
+ "autoincrement": false
+ }
+ },
+ "indexes": {
+ "beta_feedback_vault_idx": {
+ "name": "beta_feedback_vault_idx",
+ "columns": [
+ "vault_id"
+ ],
+ "isUnique": false
+ },
+ "beta_feedback_status_idx": {
+ "name": "beta_feedback_status_idx",
+ "columns": [
+ "status"
+ ],
+ "isUnique": false
+ }
+ },
+ "foreignKeys": {
+ "beta_feedback_vault_id_vaults_id_fk": {
+ "name": "beta_feedback_vault_id_vaults_id_fk",
+ "tableFrom": "beta_feedback",
+ "tableTo": "vaults",
+ "columnsFrom": [
+ "vault_id"
+ ],
+ "columnsTo": [
+ "id"
+ ],
+ "onDelete": "cascade",
+ "onUpdate": "no action"
+ }
+ },
+ "compositePrimaryKeys": {},
+ "uniqueConstraints": {},
+ "checkConstraints": {}
+ },
+ "beta_invite_counters": {
+ "name": "beta_invite_counters",
+ "columns": {
+ "invite_digest": {
+ "name": "invite_digest",
+ "type": "text",
+ "primaryKey": true,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "uses": {
+ "name": "uses",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": 0
+ },
+ "max_uses": {
+ "name": "max_uses",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "updated_at": {
+ "name": "updated_at",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": "CURRENT_TIMESTAMP"
+ }
+ },
+ "indexes": {},
+ "foreignKeys": {},
+ "compositePrimaryKeys": {},
+ "uniqueConstraints": {},
+ "checkConstraints": {}
+ },
+ "beta_runtime_settings": {
+ "name": "beta_runtime_settings",
+ "columns": {
+ "id": {
+ "name": "id",
+ "type": "text",
+ "primaryKey": true,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "signups_enabled": {
+ "name": "signups_enabled",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "updated_by_digest": {
+ "name": "updated_by_digest",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": false,
+ "autoincrement": false
+ },
+ "updated_at": {
+ "name": "updated_at",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": "CURRENT_TIMESTAMP"
+ }
+ },
+ "indexes": {},
+ "foreignKeys": {},
+ "compositePrimaryKeys": {},
+ "uniqueConstraints": {},
+ "checkConstraints": {}
+ },
+ "community_moderation_actions": {
+ "name": "community_moderation_actions",
+ "columns": {
+ "id": {
+ "name": "id",
+ "type": "text",
+ "primaryKey": true,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "story_id": {
+ "name": "story_id",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "actor_digest": {
+ "name": "actor_digest",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "action": {
+ "name": "action",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "from_status": {
+ "name": "from_status",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "to_status": {
+ "name": "to_status",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "note": {
+ "name": "note",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": "''"
+ },
+ "created_at": {
+ "name": "created_at",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": "CURRENT_TIMESTAMP"
+ }
+ },
+ "indexes": {
+ "community_moderation_story_idx": {
+ "name": "community_moderation_story_idx",
+ "columns": [
+ "story_id"
+ ],
+ "isUnique": false
+ },
+ "community_moderation_created_idx": {
+ "name": "community_moderation_created_idx",
+ "columns": [
+ "created_at"
+ ],
+ "isUnique": false
+ }
+ },
+ "foreignKeys": {
+ "community_moderation_actions_story_id_public_stories_id_fk": {
+ "name": "community_moderation_actions_story_id_public_stories_id_fk",
+ "tableFrom": "community_moderation_actions",
+ "tableTo": "public_stories",
+ "columnsFrom": [
+ "story_id"
+ ],
+ "columnsTo": [
+ "id"
+ ],
+ "onDelete": "cascade",
+ "onUpdate": "no action"
+ }
+ },
+ "compositePrimaryKeys": {},
+ "uniqueConstraints": {},
+ "checkConstraints": {}
+ },
+ "community_rate_limits": {
+ "name": "community_rate_limits",
+ "columns": {
+ "id": {
+ "name": "id",
+ "type": "text",
+ "primaryKey": true,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "vault_id": {
+ "name": "vault_id",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "action": {
+ "name": "action",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "window_key": {
+ "name": "window_key",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "count": {
+ "name": "count",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": 0
+ },
+ "updated_at": {
+ "name": "updated_at",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": "CURRENT_TIMESTAMP"
+ }
+ },
+ "indexes": {
+ "community_rate_vault_action_window_unique": {
+ "name": "community_rate_vault_action_window_unique",
+ "columns": [
+ "vault_id",
+ "action",
+ "window_key"
+ ],
+ "isUnique": true
+ },
+ "community_rate_window_idx": {
+ "name": "community_rate_window_idx",
+ "columns": [
+ "window_key"
+ ],
+ "isUnique": false
+ }
+ },
+ "foreignKeys": {
+ "community_rate_limits_vault_id_vaults_id_fk": {
+ "name": "community_rate_limits_vault_id_vaults_id_fk",
+ "tableFrom": "community_rate_limits",
+ "tableTo": "vaults",
+ "columnsFrom": [
+ "vault_id"
+ ],
+ "columnsTo": [
+ "id"
+ ],
+ "onDelete": "cascade",
+ "onUpdate": "no action"
+ }
+ },
+ "compositePrimaryKeys": {},
+ "uniqueConstraints": {},
+ "checkConstraints": {}
+ },
+ "debts": {
+ "name": "debts",
+ "columns": {
+ "id": {
+ "name": "id",
+ "type": "text",
+ "primaryKey": true,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "vault_id": {
+ "name": "vault_id",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "kind": {
+ "name": "kind",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "custom_label": {
+ "name": "custom_label",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": false,
+ "autoincrement": false
+ },
+ "currency": {
+ "name": "currency",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "original": {
+ "name": "original",
+ "type": "real",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "balance": {
+ "name": "balance",
+ "type": "real",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "monthly": {
+ "name": "monthly",
+ "type": "real",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "apr": {
+ "name": "apr",
+ "type": "real",
+ "primaryKey": false,
+ "notNull": false,
+ "autoincrement": false
+ },
+ "minimum_payment": {
+ "name": "minimum_payment",
+ "type": "real",
+ "primaryKey": false,
+ "notNull": false,
+ "autoincrement": false
+ },
+ "payment_status": {
+ "name": "payment_status",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": "'unknown'"
+ },
+ "remaining_months": {
+ "name": "remaining_months",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": false,
+ "autoincrement": false
+ },
+ "due_day": {
+ "name": "due_day",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "method": {
+ "name": "method",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "sharing_mode": {
+ "name": "sharing_mode",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": "'private'"
+ },
+ "last_paid_at": {
+ "name": "last_paid_at",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": false,
+ "autoincrement": false
+ },
+ "payments": {
+ "name": "payments",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": 0
+ },
+ "created_at": {
+ "name": "created_at",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": "CURRENT_TIMESTAMP"
+ },
+ "updated_at": {
+ "name": "updated_at",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": "CURRENT_TIMESTAMP"
+ }
+ },
+ "indexes": {
+ "debts_vault_id_idx": {
+ "name": "debts_vault_id_idx",
+ "columns": [
+ "vault_id"
+ ],
+ "isUnique": false
+ }
+ },
+ "foreignKeys": {
+ "debts_vault_id_vaults_id_fk": {
+ "name": "debts_vault_id_vaults_id_fk",
+ "tableFrom": "debts",
+ "tableTo": "vaults",
+ "columnsFrom": [
+ "vault_id"
+ ],
+ "columnsTo": [
+ "id"
+ ],
+ "onDelete": "cascade",
+ "onUpdate": "no action"
+ }
+ },
+ "compositePrimaryKeys": {},
+ "uniqueConstraints": {},
+ "checkConstraints": {}
+ },
+ "lucky_income_claims": {
+ "name": "lucky_income_claims",
+ "columns": {
+ "id": {
+ "name": "id",
+ "type": "text",
+ "primaryKey": true,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "vault_id": {
+ "name": "vault_id",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "event_date": {
+ "name": "event_date",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "created_at": {
+ "name": "created_at",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": "CURRENT_TIMESTAMP"
+ }
+ },
+ "indexes": {
+ "lucky_income_vault_day_unique": {
+ "name": "lucky_income_vault_day_unique",
+ "columns": [
+ "vault_id",
+ "event_date"
+ ],
+ "isUnique": true
+ }
+ },
+ "foreignKeys": {
+ "lucky_income_claims_vault_id_vaults_id_fk": {
+ "name": "lucky_income_claims_vault_id_vaults_id_fk",
+ "tableFrom": "lucky_income_claims",
+ "tableTo": "vaults",
+ "columnsFrom": [
+ "vault_id"
+ ],
+ "columnsTo": [
+ "id"
+ ],
+ "onDelete": "cascade",
+ "onUpdate": "no action"
+ }
+ },
+ "compositePrimaryKeys": {},
+ "uniqueConstraints": {},
+ "checkConstraints": {}
+ },
+ "owner_admins": {
+ "name": "owner_admins",
+ "columns": {
+ "id": {
+ "name": "id",
+ "type": "text",
+ "primaryKey": true,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "email_digest": {
+ "name": "email_digest",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "role": {
+ "name": "role",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": "'owner'"
+ },
+ "activated_at": {
+ "name": "activated_at",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": "CURRENT_TIMESTAMP"
+ },
+ "last_seen_at": {
+ "name": "last_seen_at",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": "CURRENT_TIMESTAMP"
+ }
+ },
+ "indexes": {
+ "owner_admins_email_digest_unique": {
+ "name": "owner_admins_email_digest_unique",
+ "columns": [
+ "email_digest"
+ ],
+ "isUnique": true
+ }
+ },
+ "foreignKeys": {},
+ "compositePrimaryKeys": {},
+ "uniqueConstraints": {},
+ "checkConstraints": {}
+ },
+ "payment_records": {
+ "name": "payment_records",
+ "columns": {
+ "id": {
+ "name": "id",
+ "type": "text",
+ "primaryKey": true,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "vault_id": {
+ "name": "vault_id",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "debt_id": {
+ "name": "debt_id",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "scheduled_date": {
+ "name": "scheduled_date",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": false,
+ "autoincrement": false
+ },
+ "confirmed_at": {
+ "name": "confirmed_at",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "event_date": {
+ "name": "event_date",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": false,
+ "autoincrement": false
+ },
+ "cash_payment": {
+ "name": "cash_payment",
+ "type": "real",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "new_balance": {
+ "name": "new_balance",
+ "type": "real",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "source": {
+ "name": "source",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": "'self_report'"
+ },
+ "income_type": {
+ "name": "income_type",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": false,
+ "autoincrement": false
+ },
+ "created_at": {
+ "name": "created_at",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": "CURRENT_TIMESTAMP"
+ }
+ },
+ "indexes": {
+ "payments_vault_id_idx": {
+ "name": "payments_vault_id_idx",
+ "columns": [
+ "vault_id"
+ ],
+ "isUnique": false
+ },
+ "payments_debt_id_idx": {
+ "name": "payments_debt_id_idx",
+ "columns": [
+ "debt_id"
+ ],
+ "isUnique": false
+ }
+ },
+ "foreignKeys": {
+ "payment_records_vault_id_vaults_id_fk": {
+ "name": "payment_records_vault_id_vaults_id_fk",
+ "tableFrom": "payment_records",
+ "tableTo": "vaults",
+ "columnsFrom": [
+ "vault_id"
+ ],
+ "columnsTo": [
+ "id"
+ ],
+ "onDelete": "cascade",
+ "onUpdate": "no action"
+ },
+ "payment_records_debt_id_debts_id_fk": {
+ "name": "payment_records_debt_id_debts_id_fk",
+ "tableFrom": "payment_records",
+ "tableTo": "debts",
+ "columnsFrom": [
+ "debt_id"
+ ],
+ "columnsTo": [
+ "id"
+ ],
+ "onDelete": "cascade",
+ "onUpdate": "no action"
+ }
+ },
+ "compositePrimaryKeys": {},
+ "uniqueConstraints": {},
+ "checkConstraints": {}
+ },
+ "policy_acceptances": {
+ "name": "policy_acceptances",
+ "columns": {
+ "id": {
+ "name": "id",
+ "type": "text",
+ "primaryKey": true,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "vault_id": {
+ "name": "vault_id",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "policy_key": {
+ "name": "policy_key",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "policy_version": {
+ "name": "policy_version",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "accepted_at": {
+ "name": "accepted_at",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": "CURRENT_TIMESTAMP"
+ }
+ },
+ "indexes": {
+ "policy_acceptance_vault_key_version_unique": {
+ "name": "policy_acceptance_vault_key_version_unique",
+ "columns": [
+ "vault_id",
+ "policy_key",
+ "policy_version"
+ ],
+ "isUnique": true
+ },
+ "policy_acceptance_vault_idx": {
+ "name": "policy_acceptance_vault_idx",
+ "columns": [
+ "vault_id"
+ ],
+ "isUnique": false
+ }
+ },
+ "foreignKeys": {
+ "policy_acceptances_vault_id_vaults_id_fk": {
+ "name": "policy_acceptances_vault_id_vaults_id_fk",
+ "tableFrom": "policy_acceptances",
+ "tableTo": "vaults",
+ "columnsFrom": [
+ "vault_id"
+ ],
+ "columnsTo": [
+ "id"
+ ],
+ "onDelete": "cascade",
+ "onUpdate": "no action"
+ }
+ },
+ "compositePrimaryKeys": {},
+ "uniqueConstraints": {},
+ "checkConstraints": {}
+ },
+ "public_stories": {
+ "name": "public_stories",
+ "columns": {
+ "id": {
+ "name": "id",
+ "type": "text",
+ "primaryKey": true,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "vault_id": {
+ "name": "vault_id",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "debt_id": {
+ "name": "debt_id",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "anonymous_name": {
+ "name": "anonymous_name",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "country_code": {
+ "name": "country_code",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": "''"
+ },
+ "debt_kind": {
+ "name": "debt_kind",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "amount_band": {
+ "name": "amount_band",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "currency": {
+ "name": "currency",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "repayment_approach": {
+ "name": "repayment_approach",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": "'other'"
+ },
+ "story_text": {
+ "name": "story_text",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "status": {
+ "name": "status",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": "'pending'"
+ },
+ "created_at": {
+ "name": "created_at",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": "CURRENT_TIMESTAMP"
+ },
+ "updated_at": {
+ "name": "updated_at",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": "CURRENT_TIMESTAMP"
+ }
+ },
+ "indexes": {
+ "public_stories_status_idx": {
+ "name": "public_stories_status_idx",
+ "columns": [
+ "status"
+ ],
+ "isUnique": false
+ },
+ "public_stories_vault_idx": {
+ "name": "public_stories_vault_idx",
+ "columns": [
+ "vault_id"
+ ],
+ "isUnique": false
+ }
+ },
+ "foreignKeys": {
+ "public_stories_vault_id_vaults_id_fk": {
+ "name": "public_stories_vault_id_vaults_id_fk",
+ "tableFrom": "public_stories",
+ "tableTo": "vaults",
+ "columnsFrom": [
+ "vault_id"
+ ],
+ "columnsTo": [
+ "id"
+ ],
+ "onDelete": "cascade",
+ "onUpdate": "no action"
+ },
+ "public_stories_debt_id_debts_id_fk": {
+ "name": "public_stories_debt_id_debts_id_fk",
+ "tableFrom": "public_stories",
+ "tableTo": "debts",
+ "columnsFrom": [
+ "debt_id"
+ ],
+ "columnsTo": [
+ "id"
+ ],
+ "onDelete": "cascade",
+ "onUpdate": "no action"
+ }
+ },
+ "compositePrimaryKeys": {},
+ "uniqueConstraints": {},
+ "checkConstraints": {}
+ },
+ "story_encouragements": {
+ "name": "story_encouragements",
+ "columns": {
+ "id": {
+ "name": "id",
+ "type": "text",
+ "primaryKey": true,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "story_id": {
+ "name": "story_id",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "vault_id": {
+ "name": "vault_id",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "created_at": {
+ "name": "created_at",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": "CURRENT_TIMESTAMP"
+ }
+ },
+ "indexes": {
+ "story_encouragement_unique": {
+ "name": "story_encouragement_unique",
+ "columns": [
+ "story_id",
+ "vault_id"
+ ],
+ "isUnique": true
+ },
+ "story_encouragement_story_idx": {
+ "name": "story_encouragement_story_idx",
+ "columns": [
+ "story_id"
+ ],
+ "isUnique": false
+ }
+ },
+ "foreignKeys": {
+ "story_encouragements_story_id_public_stories_id_fk": {
+ "name": "story_encouragements_story_id_public_stories_id_fk",
+ "tableFrom": "story_encouragements",
+ "tableTo": "public_stories",
+ "columnsFrom": [
+ "story_id"
+ ],
+ "columnsTo": [
+ "id"
+ ],
+ "onDelete": "cascade",
+ "onUpdate": "no action"
+ },
+ "story_encouragements_vault_id_vaults_id_fk": {
+ "name": "story_encouragements_vault_id_vaults_id_fk",
+ "tableFrom": "story_encouragements",
+ "tableTo": "vaults",
+ "columnsFrom": [
+ "vault_id"
+ ],
+ "columnsTo": [
+ "id"
+ ],
+ "onDelete": "cascade",
+ "onUpdate": "no action"
+ }
+ },
+ "compositePrimaryKeys": {},
+ "uniqueConstraints": {},
+ "checkConstraints": {}
+ },
+ "story_reports": {
+ "name": "story_reports",
+ "columns": {
+ "id": {
+ "name": "id",
+ "type": "text",
+ "primaryKey": true,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "story_id": {
+ "name": "story_id",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "reporter_vault_id": {
+ "name": "reporter_vault_id",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "reason": {
+ "name": "reason",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "details": {
+ "name": "details",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": "''"
+ },
+ "status": {
+ "name": "status",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": "'open'"
+ },
+ "created_at": {
+ "name": "created_at",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": "CURRENT_TIMESTAMP"
+ },
+ "resolved_at": {
+ "name": "resolved_at",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": false,
+ "autoincrement": false
+ }
+ },
+ "indexes": {
+ "story_report_unique": {
+ "name": "story_report_unique",
+ "columns": [
+ "story_id",
+ "reporter_vault_id"
+ ],
+ "isUnique": true
+ },
+ "story_reports_status_idx": {
+ "name": "story_reports_status_idx",
+ "columns": [
+ "status"
+ ],
+ "isUnique": false
+ }
+ },
+ "foreignKeys": {
+ "story_reports_story_id_public_stories_id_fk": {
+ "name": "story_reports_story_id_public_stories_id_fk",
+ "tableFrom": "story_reports",
+ "tableTo": "public_stories",
+ "columnsFrom": [
+ "story_id"
+ ],
+ "columnsTo": [
+ "id"
+ ],
+ "onDelete": "cascade",
+ "onUpdate": "no action"
+ },
+ "story_reports_reporter_vault_id_vaults_id_fk": {
+ "name": "story_reports_reporter_vault_id_vaults_id_fk",
+ "tableFrom": "story_reports",
+ "tableTo": "vaults",
+ "columnsFrom": [
+ "reporter_vault_id"
+ ],
+ "columnsTo": [
+ "id"
+ ],
+ "onDelete": "cascade",
+ "onUpdate": "no action"
+ }
+ },
+ "compositePrimaryKeys": {},
+ "uniqueConstraints": {},
+ "checkConstraints": {}
+ },
+ "vaults": {
+ "name": "vaults",
+ "columns": {
+ "id": {
+ "name": "id",
+ "type": "text",
+ "primaryKey": true,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "recovery_hash": {
+ "name": "recovery_hash",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "alias": {
+ "name": "alias",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "region": {
+ "name": "region",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "pressure": {
+ "name": "pressure",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": "''"
+ },
+ "position_x": {
+ "name": "position_x",
+ "type": "real",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": 47
+ },
+ "position_y": {
+ "name": "position_y",
+ "type": "real",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": 63
+ },
+ "locale": {
+ "name": "locale",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": "'zh'"
+ },
+ "country_code": {
+ "name": "country_code",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": "''"
+ },
+ "country_name": {
+ "name": "country_name",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": "''"
+ },
+ "display_currency": {
+ "name": "display_currency",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": "'CNY'"
+ },
+ "monthly_income": {
+ "name": "monthly_income",
+ "type": "real",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": 0
+ },
+ "monthly_expenses": {
+ "name": "monthly_expenses",
+ "type": "real",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": 0
+ },
+ "discovery_consent": {
+ "name": "discovery_consent",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": false
+ },
+ "created_at": {
+ "name": "created_at",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": "CURRENT_TIMESTAMP"
+ },
+ "updated_at": {
+ "name": "updated_at",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": "CURRENT_TIMESTAMP"
+ }
+ },
+ "indexes": {
+ "vaults_recovery_hash_unique": {
+ "name": "vaults_recovery_hash_unique",
+ "columns": [
+ "recovery_hash"
+ ],
+ "isUnique": true
+ }
+ },
+ "foreignKeys": {},
+ "compositePrimaryKeys": {},
+ "uniqueConstraints": {},
+ "checkConstraints": {}
+ },
+ "world_category_candidates": {
+ "name": "world_category_candidates",
+ "columns": {
+ "id": {
+ "name": "id",
+ "type": "text",
+ "primaryKey": true,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "canonical_key": {
+ "name": "canonical_key",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "parent_kind": {
+ "name": "parent_kind",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": "'other'"
+ },
+ "name_zh": {
+ "name": "name_zh",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "name_en": {
+ "name": "name_en",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "description_zh": {
+ "name": "description_zh",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": "''"
+ },
+ "description_en": {
+ "name": "description_en",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": "''"
+ },
+ "status": {
+ "name": "status",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": "'candidate'"
+ },
+ "stage": {
+ "name": "stage",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": 0
+ },
+ "confidence": {
+ "name": "confidence",
+ "type": "real",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": 0
+ },
+ "unique_vaults": {
+ "name": "unique_vaults",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": 0
+ },
+ "region_count": {
+ "name": "region_count",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": 0
+ },
+ "mention_count": {
+ "name": "mention_count",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": 0
+ },
+ "emergence_score": {
+ "name": "emergence_score",
+ "type": "real",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": 0
+ },
+ "weight_profile_id": {
+ "name": "weight_profile_id",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": false,
+ "autoincrement": false
+ },
+ "merged_into_id": {
+ "name": "merged_into_id",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": false,
+ "autoincrement": false
+ },
+ "proposed_at": {
+ "name": "proposed_at",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": "CURRENT_TIMESTAMP"
+ },
+ "reviewed_at": {
+ "name": "reviewed_at",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": false,
+ "autoincrement": false
+ },
+ "published_at": {
+ "name": "published_at",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": false,
+ "autoincrement": false
+ },
+ "updated_at": {
+ "name": "updated_at",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": "CURRENT_TIMESTAMP"
+ }
+ },
+ "indexes": {
+ "world_category_candidates_canonical_key_unique": {
+ "name": "world_category_candidates_canonical_key_unique",
+ "columns": [
+ "canonical_key"
+ ],
+ "isUnique": true
+ },
+ "world_candidates_status_idx": {
+ "name": "world_candidates_status_idx",
+ "columns": [
+ "status"
+ ],
+ "isUnique": false
+ },
+ "world_candidates_score_idx": {
+ "name": "world_candidates_score_idx",
+ "columns": [
+ "emergence_score"
+ ],
+ "isUnique": false
+ }
+ },
+ "foreignKeys": {
+ "world_category_candidates_weight_profile_id_world_weight_profiles_id_fk": {
+ "name": "world_category_candidates_weight_profile_id_world_weight_profiles_id_fk",
+ "tableFrom": "world_category_candidates",
+ "tableTo": "world_weight_profiles",
+ "columnsFrom": [
+ "weight_profile_id"
+ ],
+ "columnsTo": [
+ "id"
+ ],
+ "onDelete": "no action",
+ "onUpdate": "no action"
+ }
+ },
+ "compositePrimaryKeys": {},
+ "uniqueConstraints": {},
+ "checkConstraints": {}
+ },
+ "world_growth_events": {
+ "name": "world_growth_events",
+ "columns": {
+ "id": {
+ "name": "id",
+ "type": "text",
+ "primaryKey": true,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "candidate_id": {
+ "name": "candidate_id",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "event_type": {
+ "name": "event_type",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "from_stage": {
+ "name": "from_stage",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": false,
+ "autoincrement": false
+ },
+ "to_stage": {
+ "name": "to_stage",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": false,
+ "autoincrement": false
+ },
+ "actor_type": {
+ "name": "actor_type",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": "'system'"
+ },
+ "weight_profile_id": {
+ "name": "weight_profile_id",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": false,
+ "autoincrement": false
+ },
+ "evidence_json": {
+ "name": "evidence_json",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": "'{}'"
+ },
+ "reason": {
+ "name": "reason",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": "''"
+ },
+ "created_at": {
+ "name": "created_at",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": "CURRENT_TIMESTAMP"
+ }
+ },
+ "indexes": {
+ "world_events_candidate_idx": {
+ "name": "world_events_candidate_idx",
+ "columns": [
+ "candidate_id"
+ ],
+ "isUnique": false
+ }
+ },
+ "foreignKeys": {
+ "world_growth_events_candidate_id_world_category_candidates_id_fk": {
+ "name": "world_growth_events_candidate_id_world_category_candidates_id_fk",
+ "tableFrom": "world_growth_events",
+ "tableTo": "world_category_candidates",
+ "columnsFrom": [
+ "candidate_id"
+ ],
+ "columnsTo": [
+ "id"
+ ],
+ "onDelete": "cascade",
+ "onUpdate": "no action"
+ },
+ "world_growth_events_weight_profile_id_world_weight_profiles_id_fk": {
+ "name": "world_growth_events_weight_profile_id_world_weight_profiles_id_fk",
+ "tableFrom": "world_growth_events",
+ "tableTo": "world_weight_profiles",
+ "columnsFrom": [
+ "weight_profile_id"
+ ],
+ "columnsTo": [
+ "id"
+ ],
+ "onDelete": "no action",
+ "onUpdate": "no action"
+ }
+ },
+ "compositePrimaryKeys": {},
+ "uniqueConstraints": {},
+ "checkConstraints": {}
+ },
+ "world_signal_assignments": {
+ "name": "world_signal_assignments",
+ "columns": {
+ "id": {
+ "name": "id",
+ "type": "text",
+ "primaryKey": true,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "vault_id": {
+ "name": "vault_id",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "debt_id": {
+ "name": "debt_id",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "candidate_id": {
+ "name": "candidate_id",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "confidence": {
+ "name": "confidence",
+ "type": "real",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "assignment_source": {
+ "name": "assignment_source",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": "'ai'"
+ },
+ "taxonomy_version": {
+ "name": "taxonomy_version",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": 1
+ },
+ "created_at": {
+ "name": "created_at",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": "CURRENT_TIMESTAMP"
+ },
+ "updated_at": {
+ "name": "updated_at",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": "CURRENT_TIMESTAMP"
+ }
+ },
+ "indexes": {
+ "world_signal_assignments_debt_id_unique": {
+ "name": "world_signal_assignments_debt_id_unique",
+ "columns": [
+ "debt_id"
+ ],
+ "isUnique": true
+ },
+ "world_signals_vault_idx": {
+ "name": "world_signals_vault_idx",
+ "columns": [
+ "vault_id"
+ ],
+ "isUnique": false
+ },
+ "world_signals_candidate_idx": {
+ "name": "world_signals_candidate_idx",
+ "columns": [
+ "candidate_id"
+ ],
+ "isUnique": false
+ }
+ },
+ "foreignKeys": {
+ "world_signal_assignments_vault_id_vaults_id_fk": {
+ "name": "world_signal_assignments_vault_id_vaults_id_fk",
+ "tableFrom": "world_signal_assignments",
+ "tableTo": "vaults",
+ "columnsFrom": [
+ "vault_id"
+ ],
+ "columnsTo": [
+ "id"
+ ],
+ "onDelete": "cascade",
+ "onUpdate": "no action"
+ },
+ "world_signal_assignments_debt_id_debts_id_fk": {
+ "name": "world_signal_assignments_debt_id_debts_id_fk",
+ "tableFrom": "world_signal_assignments",
+ "tableTo": "debts",
+ "columnsFrom": [
+ "debt_id"
+ ],
+ "columnsTo": [
+ "id"
+ ],
+ "onDelete": "cascade",
+ "onUpdate": "no action"
+ },
+ "world_signal_assignments_candidate_id_world_category_candidates_id_fk": {
+ "name": "world_signal_assignments_candidate_id_world_category_candidates_id_fk",
+ "tableFrom": "world_signal_assignments",
+ "tableTo": "world_category_candidates",
+ "columnsFrom": [
+ "candidate_id"
+ ],
+ "columnsTo": [
+ "id"
+ ],
+ "onDelete": "cascade",
+ "onUpdate": "no action"
+ }
+ },
+ "compositePrimaryKeys": {},
+ "uniqueConstraints": {},
+ "checkConstraints": {}
+ },
+ "world_weight_profiles": {
+ "name": "world_weight_profiles",
+ "columns": {
+ "id": {
+ "name": "id",
+ "type": "text",
+ "primaryKey": true,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "version": {
+ "name": "version",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "status": {
+ "name": "status",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": "'draft'"
+ },
+ "frequency_weight": {
+ "name": "frequency_weight",
+ "type": "real",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "growth_weight": {
+ "name": "growth_weight",
+ "type": "real",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "geography_weight": {
+ "name": "geography_weight",
+ "type": "real",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "recurrence_weight": {
+ "name": "recurrence_weight",
+ "type": "real",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "connection_weight": {
+ "name": "connection_weight",
+ "type": "real",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "quality_weight": {
+ "name": "quality_weight",
+ "type": "real",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "proposed_by": {
+ "name": "proposed_by",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": "'human'"
+ },
+ "model_ref": {
+ "name": "model_ref",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": false,
+ "autoincrement": false
+ },
+ "rationale": {
+ "name": "rationale",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": "''"
+ },
+ "created_at": {
+ "name": "created_at",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": "CURRENT_TIMESTAMP"
+ },
+ "activated_at": {
+ "name": "activated_at",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": false,
+ "autoincrement": false
+ }
+ },
+ "indexes": {
+ "world_weight_profiles_version_unique": {
+ "name": "world_weight_profiles_version_unique",
+ "columns": [
+ "version"
+ ],
+ "isUnique": true
+ }
+ },
+ "foreignKeys": {},
+ "compositePrimaryKeys": {},
+ "uniqueConstraints": {},
+ "checkConstraints": {}
+ }
+ },
+ "views": {},
+ "enums": {},
+ "_meta": {
+ "schemas": {},
+ "tables": {},
+ "columns": {}
+ },
+ "internal": {
+ "indexes": {}
+ }
+}
\ No newline at end of file
diff --git a/drizzle/meta/0013_snapshot.json b/drizzle/meta/0013_snapshot.json
new file mode 100644
index 0000000..d524d7e
--- /dev/null
+++ b/drizzle/meta/0013_snapshot.json
@@ -0,0 +1,2510 @@
+{
+ "version": "6",
+ "dialect": "sqlite",
+ "id": "a49d9d15-663c-4dbf-a688-e36d6280964a",
+ "prevId": "6dc4ae81-0c8d-4705-ba16-fd1e434e718c",
+ "tables": {
+ "account_auth_limits": {
+ "name": "account_auth_limits",
+ "columns": {
+ "limit_key": {
+ "name": "limit_key",
+ "type": "text",
+ "primaryKey": true,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "action": {
+ "name": "action",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "window_key": {
+ "name": "window_key",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "attempts": {
+ "name": "attempts",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": 0
+ },
+ "updated_at": {
+ "name": "updated_at",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": "CURRENT_TIMESTAMP"
+ }
+ },
+ "indexes": {
+ "account_auth_limits_window_idx": {
+ "name": "account_auth_limits_window_idx",
+ "columns": [
+ "window_key"
+ ],
+ "isUnique": false
+ }
+ },
+ "foreignKeys": {},
+ "compositePrimaryKeys": {},
+ "uniqueConstraints": {},
+ "checkConstraints": {}
+ },
+ "account_sessions": {
+ "name": "account_sessions",
+ "columns": {
+ "id": {
+ "name": "id",
+ "type": "text",
+ "primaryKey": true,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "account_id": {
+ "name": "account_id",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "token_hash": {
+ "name": "token_hash",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "expires_at": {
+ "name": "expires_at",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "created_at": {
+ "name": "created_at",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": "CURRENT_TIMESTAMP"
+ },
+ "last_seen_at": {
+ "name": "last_seen_at",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": "CURRENT_TIMESTAMP"
+ }
+ },
+ "indexes": {
+ "account_sessions_token_hash_unique": {
+ "name": "account_sessions_token_hash_unique",
+ "columns": [
+ "token_hash"
+ ],
+ "isUnique": true
+ },
+ "account_sessions_account_idx": {
+ "name": "account_sessions_account_idx",
+ "columns": [
+ "account_id"
+ ],
+ "isUnique": false
+ },
+ "account_sessions_expires_idx": {
+ "name": "account_sessions_expires_idx",
+ "columns": [
+ "expires_at"
+ ],
+ "isUnique": false
+ }
+ },
+ "foreignKeys": {
+ "account_sessions_account_id_accounts_id_fk": {
+ "name": "account_sessions_account_id_accounts_id_fk",
+ "tableFrom": "account_sessions",
+ "tableTo": "accounts",
+ "columnsFrom": [
+ "account_id"
+ ],
+ "columnsTo": [
+ "id"
+ ],
+ "onDelete": "cascade",
+ "onUpdate": "no action"
+ }
+ },
+ "compositePrimaryKeys": {},
+ "uniqueConstraints": {},
+ "checkConstraints": {}
+ },
+ "account_vaults": {
+ "name": "account_vaults",
+ "columns": {
+ "account_id": {
+ "name": "account_id",
+ "type": "text",
+ "primaryKey": true,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "vault_id": {
+ "name": "vault_id",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "linked_at": {
+ "name": "linked_at",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": "CURRENT_TIMESTAMP"
+ }
+ },
+ "indexes": {
+ "account_vaults_vault_id_unique": {
+ "name": "account_vaults_vault_id_unique",
+ "columns": [
+ "vault_id"
+ ],
+ "isUnique": true
+ },
+ "account_vaults_vault_idx": {
+ "name": "account_vaults_vault_idx",
+ "columns": [
+ "vault_id"
+ ],
+ "isUnique": false
+ }
+ },
+ "foreignKeys": {
+ "account_vaults_account_id_accounts_id_fk": {
+ "name": "account_vaults_account_id_accounts_id_fk",
+ "tableFrom": "account_vaults",
+ "tableTo": "accounts",
+ "columnsFrom": [
+ "account_id"
+ ],
+ "columnsTo": [
+ "id"
+ ],
+ "onDelete": "cascade",
+ "onUpdate": "no action"
+ },
+ "account_vaults_vault_id_vaults_id_fk": {
+ "name": "account_vaults_vault_id_vaults_id_fk",
+ "tableFrom": "account_vaults",
+ "tableTo": "vaults",
+ "columnsFrom": [
+ "vault_id"
+ ],
+ "columnsTo": [
+ "id"
+ ],
+ "onDelete": "cascade",
+ "onUpdate": "no action"
+ }
+ },
+ "compositePrimaryKeys": {},
+ "uniqueConstraints": {},
+ "checkConstraints": {}
+ },
+ "accounts": {
+ "name": "accounts",
+ "columns": {
+ "id": {
+ "name": "id",
+ "type": "text",
+ "primaryKey": true,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "user_code": {
+ "name": "user_code",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "username": {
+ "name": "username",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "username_normalized": {
+ "name": "username_normalized",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "password_hash": {
+ "name": "password_hash",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "password_salt": {
+ "name": "password_salt",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "password_iterations": {
+ "name": "password_iterations",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "status": {
+ "name": "status",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": "'active'"
+ },
+ "created_at": {
+ "name": "created_at",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": "CURRENT_TIMESTAMP"
+ },
+ "updated_at": {
+ "name": "updated_at",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": "CURRENT_TIMESTAMP"
+ },
+ "last_login_at": {
+ "name": "last_login_at",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": false,
+ "autoincrement": false
+ },
+ "last_seen_at": {
+ "name": "last_seen_at",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": false,
+ "autoincrement": false
+ }
+ },
+ "indexes": {
+ "accounts_user_code_unique": {
+ "name": "accounts_user_code_unique",
+ "columns": [
+ "user_code"
+ ],
+ "isUnique": true
+ },
+ "accounts_username_normalized_unique": {
+ "name": "accounts_username_normalized_unique",
+ "columns": [
+ "username_normalized"
+ ],
+ "isUnique": true
+ },
+ "accounts_created_idx": {
+ "name": "accounts_created_idx",
+ "columns": [
+ "created_at"
+ ],
+ "isUnique": false
+ }
+ },
+ "foreignKeys": {},
+ "compositePrimaryKeys": {},
+ "uniqueConstraints": {},
+ "checkConstraints": {}
+ },
+ "ai_daily_usage": {
+ "name": "ai_daily_usage",
+ "columns": {
+ "id": {
+ "name": "id",
+ "type": "text",
+ "primaryKey": true,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "vault_id": {
+ "name": "vault_id",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "usage_date": {
+ "name": "usage_date",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "request_count": {
+ "name": "request_count",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": 0
+ },
+ "input_tokens": {
+ "name": "input_tokens",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": 0
+ },
+ "output_tokens": {
+ "name": "output_tokens",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": 0
+ },
+ "updated_at": {
+ "name": "updated_at",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": "CURRENT_TIMESTAMP"
+ }
+ },
+ "indexes": {
+ "ai_daily_usage_vault_date_unique": {
+ "name": "ai_daily_usage_vault_date_unique",
+ "columns": [
+ "vault_id",
+ "usage_date"
+ ],
+ "isUnique": true
+ },
+ "ai_daily_usage_date_idx": {
+ "name": "ai_daily_usage_date_idx",
+ "columns": [
+ "usage_date"
+ ],
+ "isUnique": false
+ }
+ },
+ "foreignKeys": {
+ "ai_daily_usage_vault_id_vaults_id_fk": {
+ "name": "ai_daily_usage_vault_id_vaults_id_fk",
+ "tableFrom": "ai_daily_usage",
+ "tableTo": "vaults",
+ "columnsFrom": [
+ "vault_id"
+ ],
+ "columnsTo": [
+ "id"
+ ],
+ "onDelete": "cascade",
+ "onUpdate": "no action"
+ }
+ },
+ "compositePrimaryKeys": {},
+ "uniqueConstraints": {},
+ "checkConstraints": {}
+ },
+ "beta_enrollments": {
+ "name": "beta_enrollments",
+ "columns": {
+ "id": {
+ "name": "id",
+ "type": "text",
+ "primaryKey": true,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "vault_id": {
+ "name": "vault_id",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "invite_digest": {
+ "name": "invite_digest",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "consent_version": {
+ "name": "consent_version",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "created_at": {
+ "name": "created_at",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": "CURRENT_TIMESTAMP"
+ }
+ },
+ "indexes": {
+ "beta_enrollments_vault_id_unique": {
+ "name": "beta_enrollments_vault_id_unique",
+ "columns": [
+ "vault_id"
+ ],
+ "isUnique": true
+ },
+ "beta_enrollments_created_idx": {
+ "name": "beta_enrollments_created_idx",
+ "columns": [
+ "created_at"
+ ],
+ "isUnique": false
+ }
+ },
+ "foreignKeys": {
+ "beta_enrollments_vault_id_vaults_id_fk": {
+ "name": "beta_enrollments_vault_id_vaults_id_fk",
+ "tableFrom": "beta_enrollments",
+ "tableTo": "vaults",
+ "columnsFrom": [
+ "vault_id"
+ ],
+ "columnsTo": [
+ "id"
+ ],
+ "onDelete": "cascade",
+ "onUpdate": "no action"
+ }
+ },
+ "compositePrimaryKeys": {},
+ "uniqueConstraints": {},
+ "checkConstraints": {}
+ },
+ "beta_feedback": {
+ "name": "beta_feedback",
+ "columns": {
+ "id": {
+ "name": "id",
+ "type": "text",
+ "primaryKey": true,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "vault_id": {
+ "name": "vault_id",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "category": {
+ "name": "category",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "rating": {
+ "name": "rating",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "message": {
+ "name": "message",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "page_path": {
+ "name": "page_path",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": "'/'"
+ },
+ "status": {
+ "name": "status",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": "'open'"
+ },
+ "created_at": {
+ "name": "created_at",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": "CURRENT_TIMESTAMP"
+ },
+ "resolved_at": {
+ "name": "resolved_at",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": false,
+ "autoincrement": false
+ }
+ },
+ "indexes": {
+ "beta_feedback_vault_idx": {
+ "name": "beta_feedback_vault_idx",
+ "columns": [
+ "vault_id"
+ ],
+ "isUnique": false
+ },
+ "beta_feedback_status_idx": {
+ "name": "beta_feedback_status_idx",
+ "columns": [
+ "status"
+ ],
+ "isUnique": false
+ }
+ },
+ "foreignKeys": {
+ "beta_feedback_vault_id_vaults_id_fk": {
+ "name": "beta_feedback_vault_id_vaults_id_fk",
+ "tableFrom": "beta_feedback",
+ "tableTo": "vaults",
+ "columnsFrom": [
+ "vault_id"
+ ],
+ "columnsTo": [
+ "id"
+ ],
+ "onDelete": "cascade",
+ "onUpdate": "no action"
+ }
+ },
+ "compositePrimaryKeys": {},
+ "uniqueConstraints": {},
+ "checkConstraints": {}
+ },
+ "beta_invite_counters": {
+ "name": "beta_invite_counters",
+ "columns": {
+ "invite_digest": {
+ "name": "invite_digest",
+ "type": "text",
+ "primaryKey": true,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "uses": {
+ "name": "uses",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": 0
+ },
+ "max_uses": {
+ "name": "max_uses",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "updated_at": {
+ "name": "updated_at",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": "CURRENT_TIMESTAMP"
+ }
+ },
+ "indexes": {},
+ "foreignKeys": {},
+ "compositePrimaryKeys": {},
+ "uniqueConstraints": {},
+ "checkConstraints": {}
+ },
+ "beta_runtime_settings": {
+ "name": "beta_runtime_settings",
+ "columns": {
+ "id": {
+ "name": "id",
+ "type": "text",
+ "primaryKey": true,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "signups_enabled": {
+ "name": "signups_enabled",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "updated_by_digest": {
+ "name": "updated_by_digest",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": false,
+ "autoincrement": false
+ },
+ "updated_at": {
+ "name": "updated_at",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": "CURRENT_TIMESTAMP"
+ }
+ },
+ "indexes": {},
+ "foreignKeys": {},
+ "compositePrimaryKeys": {},
+ "uniqueConstraints": {},
+ "checkConstraints": {}
+ },
+ "community_moderation_actions": {
+ "name": "community_moderation_actions",
+ "columns": {
+ "id": {
+ "name": "id",
+ "type": "text",
+ "primaryKey": true,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "story_id": {
+ "name": "story_id",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "actor_digest": {
+ "name": "actor_digest",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "action": {
+ "name": "action",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "from_status": {
+ "name": "from_status",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "to_status": {
+ "name": "to_status",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "note": {
+ "name": "note",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": "''"
+ },
+ "created_at": {
+ "name": "created_at",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": "CURRENT_TIMESTAMP"
+ }
+ },
+ "indexes": {
+ "community_moderation_story_idx": {
+ "name": "community_moderation_story_idx",
+ "columns": [
+ "story_id"
+ ],
+ "isUnique": false
+ },
+ "community_moderation_created_idx": {
+ "name": "community_moderation_created_idx",
+ "columns": [
+ "created_at"
+ ],
+ "isUnique": false
+ }
+ },
+ "foreignKeys": {
+ "community_moderation_actions_story_id_public_stories_id_fk": {
+ "name": "community_moderation_actions_story_id_public_stories_id_fk",
+ "tableFrom": "community_moderation_actions",
+ "tableTo": "public_stories",
+ "columnsFrom": [
+ "story_id"
+ ],
+ "columnsTo": [
+ "id"
+ ],
+ "onDelete": "cascade",
+ "onUpdate": "no action"
+ }
+ },
+ "compositePrimaryKeys": {},
+ "uniqueConstraints": {},
+ "checkConstraints": {}
+ },
+ "community_rate_limits": {
+ "name": "community_rate_limits",
+ "columns": {
+ "id": {
+ "name": "id",
+ "type": "text",
+ "primaryKey": true,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "vault_id": {
+ "name": "vault_id",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "action": {
+ "name": "action",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "window_key": {
+ "name": "window_key",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "count": {
+ "name": "count",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": 0
+ },
+ "updated_at": {
+ "name": "updated_at",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": "CURRENT_TIMESTAMP"
+ }
+ },
+ "indexes": {
+ "community_rate_vault_action_window_unique": {
+ "name": "community_rate_vault_action_window_unique",
+ "columns": [
+ "vault_id",
+ "action",
+ "window_key"
+ ],
+ "isUnique": true
+ },
+ "community_rate_window_idx": {
+ "name": "community_rate_window_idx",
+ "columns": [
+ "window_key"
+ ],
+ "isUnique": false
+ }
+ },
+ "foreignKeys": {
+ "community_rate_limits_vault_id_vaults_id_fk": {
+ "name": "community_rate_limits_vault_id_vaults_id_fk",
+ "tableFrom": "community_rate_limits",
+ "tableTo": "vaults",
+ "columnsFrom": [
+ "vault_id"
+ ],
+ "columnsTo": [
+ "id"
+ ],
+ "onDelete": "cascade",
+ "onUpdate": "no action"
+ }
+ },
+ "compositePrimaryKeys": {},
+ "uniqueConstraints": {},
+ "checkConstraints": {}
+ },
+ "debts": {
+ "name": "debts",
+ "columns": {
+ "id": {
+ "name": "id",
+ "type": "text",
+ "primaryKey": true,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "vault_id": {
+ "name": "vault_id",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "kind": {
+ "name": "kind",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "custom_label": {
+ "name": "custom_label",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": false,
+ "autoincrement": false
+ },
+ "currency": {
+ "name": "currency",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "original": {
+ "name": "original",
+ "type": "real",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "balance": {
+ "name": "balance",
+ "type": "real",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "monthly": {
+ "name": "monthly",
+ "type": "real",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "apr": {
+ "name": "apr",
+ "type": "real",
+ "primaryKey": false,
+ "notNull": false,
+ "autoincrement": false
+ },
+ "minimum_payment": {
+ "name": "minimum_payment",
+ "type": "real",
+ "primaryKey": false,
+ "notNull": false,
+ "autoincrement": false
+ },
+ "payment_status": {
+ "name": "payment_status",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": "'unknown'"
+ },
+ "remaining_months": {
+ "name": "remaining_months",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": false,
+ "autoincrement": false
+ },
+ "due_day": {
+ "name": "due_day",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "method": {
+ "name": "method",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "sharing_mode": {
+ "name": "sharing_mode",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": "'private'"
+ },
+ "last_paid_at": {
+ "name": "last_paid_at",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": false,
+ "autoincrement": false
+ },
+ "payments": {
+ "name": "payments",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": 0
+ },
+ "created_at": {
+ "name": "created_at",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": "CURRENT_TIMESTAMP"
+ },
+ "updated_at": {
+ "name": "updated_at",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": "CURRENT_TIMESTAMP"
+ }
+ },
+ "indexes": {
+ "debts_vault_id_idx": {
+ "name": "debts_vault_id_idx",
+ "columns": [
+ "vault_id"
+ ],
+ "isUnique": false
+ }
+ },
+ "foreignKeys": {
+ "debts_vault_id_vaults_id_fk": {
+ "name": "debts_vault_id_vaults_id_fk",
+ "tableFrom": "debts",
+ "tableTo": "vaults",
+ "columnsFrom": [
+ "vault_id"
+ ],
+ "columnsTo": [
+ "id"
+ ],
+ "onDelete": "cascade",
+ "onUpdate": "no action"
+ }
+ },
+ "compositePrimaryKeys": {},
+ "uniqueConstraints": {},
+ "checkConstraints": {}
+ },
+ "lucky_income_claims": {
+ "name": "lucky_income_claims",
+ "columns": {
+ "id": {
+ "name": "id",
+ "type": "text",
+ "primaryKey": true,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "vault_id": {
+ "name": "vault_id",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "event_date": {
+ "name": "event_date",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "created_at": {
+ "name": "created_at",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": "CURRENT_TIMESTAMP"
+ }
+ },
+ "indexes": {
+ "lucky_income_vault_day_unique": {
+ "name": "lucky_income_vault_day_unique",
+ "columns": [
+ "vault_id",
+ "event_date"
+ ],
+ "isUnique": true
+ }
+ },
+ "foreignKeys": {
+ "lucky_income_claims_vault_id_vaults_id_fk": {
+ "name": "lucky_income_claims_vault_id_vaults_id_fk",
+ "tableFrom": "lucky_income_claims",
+ "tableTo": "vaults",
+ "columnsFrom": [
+ "vault_id"
+ ],
+ "columnsTo": [
+ "id"
+ ],
+ "onDelete": "cascade",
+ "onUpdate": "no action"
+ }
+ },
+ "compositePrimaryKeys": {},
+ "uniqueConstraints": {},
+ "checkConstraints": {}
+ },
+ "owner_admins": {
+ "name": "owner_admins",
+ "columns": {
+ "id": {
+ "name": "id",
+ "type": "text",
+ "primaryKey": true,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "email_digest": {
+ "name": "email_digest",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "role": {
+ "name": "role",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": "'owner'"
+ },
+ "activated_at": {
+ "name": "activated_at",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": "CURRENT_TIMESTAMP"
+ },
+ "last_seen_at": {
+ "name": "last_seen_at",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": "CURRENT_TIMESTAMP"
+ }
+ },
+ "indexes": {
+ "owner_admins_email_digest_unique": {
+ "name": "owner_admins_email_digest_unique",
+ "columns": [
+ "email_digest"
+ ],
+ "isUnique": true
+ }
+ },
+ "foreignKeys": {},
+ "compositePrimaryKeys": {},
+ "uniqueConstraints": {},
+ "checkConstraints": {}
+ },
+ "payment_records": {
+ "name": "payment_records",
+ "columns": {
+ "id": {
+ "name": "id",
+ "type": "text",
+ "primaryKey": true,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "vault_id": {
+ "name": "vault_id",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "debt_id": {
+ "name": "debt_id",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "scheduled_date": {
+ "name": "scheduled_date",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": false,
+ "autoincrement": false
+ },
+ "confirmed_at": {
+ "name": "confirmed_at",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "event_date": {
+ "name": "event_date",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": false,
+ "autoincrement": false
+ },
+ "cash_payment": {
+ "name": "cash_payment",
+ "type": "real",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "new_balance": {
+ "name": "new_balance",
+ "type": "real",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "source": {
+ "name": "source",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": "'self_report'"
+ },
+ "income_type": {
+ "name": "income_type",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": false,
+ "autoincrement": false
+ },
+ "created_at": {
+ "name": "created_at",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": "CURRENT_TIMESTAMP"
+ }
+ },
+ "indexes": {
+ "payments_vault_id_idx": {
+ "name": "payments_vault_id_idx",
+ "columns": [
+ "vault_id"
+ ],
+ "isUnique": false
+ },
+ "payments_debt_id_idx": {
+ "name": "payments_debt_id_idx",
+ "columns": [
+ "debt_id"
+ ],
+ "isUnique": false
+ }
+ },
+ "foreignKeys": {
+ "payment_records_vault_id_vaults_id_fk": {
+ "name": "payment_records_vault_id_vaults_id_fk",
+ "tableFrom": "payment_records",
+ "tableTo": "vaults",
+ "columnsFrom": [
+ "vault_id"
+ ],
+ "columnsTo": [
+ "id"
+ ],
+ "onDelete": "cascade",
+ "onUpdate": "no action"
+ },
+ "payment_records_debt_id_debts_id_fk": {
+ "name": "payment_records_debt_id_debts_id_fk",
+ "tableFrom": "payment_records",
+ "tableTo": "debts",
+ "columnsFrom": [
+ "debt_id"
+ ],
+ "columnsTo": [
+ "id"
+ ],
+ "onDelete": "cascade",
+ "onUpdate": "no action"
+ }
+ },
+ "compositePrimaryKeys": {},
+ "uniqueConstraints": {},
+ "checkConstraints": {}
+ },
+ "policy_acceptances": {
+ "name": "policy_acceptances",
+ "columns": {
+ "id": {
+ "name": "id",
+ "type": "text",
+ "primaryKey": true,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "vault_id": {
+ "name": "vault_id",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "policy_key": {
+ "name": "policy_key",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "policy_version": {
+ "name": "policy_version",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "accepted_at": {
+ "name": "accepted_at",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": "CURRENT_TIMESTAMP"
+ }
+ },
+ "indexes": {
+ "policy_acceptance_vault_key_version_unique": {
+ "name": "policy_acceptance_vault_key_version_unique",
+ "columns": [
+ "vault_id",
+ "policy_key",
+ "policy_version"
+ ],
+ "isUnique": true
+ },
+ "policy_acceptance_vault_idx": {
+ "name": "policy_acceptance_vault_idx",
+ "columns": [
+ "vault_id"
+ ],
+ "isUnique": false
+ }
+ },
+ "foreignKeys": {
+ "policy_acceptances_vault_id_vaults_id_fk": {
+ "name": "policy_acceptances_vault_id_vaults_id_fk",
+ "tableFrom": "policy_acceptances",
+ "tableTo": "vaults",
+ "columnsFrom": [
+ "vault_id"
+ ],
+ "columnsTo": [
+ "id"
+ ],
+ "onDelete": "cascade",
+ "onUpdate": "no action"
+ }
+ },
+ "compositePrimaryKeys": {},
+ "uniqueConstraints": {},
+ "checkConstraints": {}
+ },
+ "public_stories": {
+ "name": "public_stories",
+ "columns": {
+ "id": {
+ "name": "id",
+ "type": "text",
+ "primaryKey": true,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "vault_id": {
+ "name": "vault_id",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "debt_id": {
+ "name": "debt_id",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "anonymous_name": {
+ "name": "anonymous_name",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "country_code": {
+ "name": "country_code",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": "''"
+ },
+ "debt_kind": {
+ "name": "debt_kind",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "amount_band": {
+ "name": "amount_band",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "currency": {
+ "name": "currency",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "repayment_approach": {
+ "name": "repayment_approach",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": "'other'"
+ },
+ "story_text": {
+ "name": "story_text",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "status": {
+ "name": "status",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": "'pending'"
+ },
+ "created_at": {
+ "name": "created_at",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": "CURRENT_TIMESTAMP"
+ },
+ "updated_at": {
+ "name": "updated_at",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": "CURRENT_TIMESTAMP"
+ }
+ },
+ "indexes": {
+ "public_stories_status_idx": {
+ "name": "public_stories_status_idx",
+ "columns": [
+ "status"
+ ],
+ "isUnique": false
+ },
+ "public_stories_vault_idx": {
+ "name": "public_stories_vault_idx",
+ "columns": [
+ "vault_id"
+ ],
+ "isUnique": false
+ }
+ },
+ "foreignKeys": {
+ "public_stories_vault_id_vaults_id_fk": {
+ "name": "public_stories_vault_id_vaults_id_fk",
+ "tableFrom": "public_stories",
+ "tableTo": "vaults",
+ "columnsFrom": [
+ "vault_id"
+ ],
+ "columnsTo": [
+ "id"
+ ],
+ "onDelete": "cascade",
+ "onUpdate": "no action"
+ },
+ "public_stories_debt_id_debts_id_fk": {
+ "name": "public_stories_debt_id_debts_id_fk",
+ "tableFrom": "public_stories",
+ "tableTo": "debts",
+ "columnsFrom": [
+ "debt_id"
+ ],
+ "columnsTo": [
+ "id"
+ ],
+ "onDelete": "cascade",
+ "onUpdate": "no action"
+ }
+ },
+ "compositePrimaryKeys": {},
+ "uniqueConstraints": {},
+ "checkConstraints": {}
+ },
+ "story_encouragements": {
+ "name": "story_encouragements",
+ "columns": {
+ "id": {
+ "name": "id",
+ "type": "text",
+ "primaryKey": true,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "story_id": {
+ "name": "story_id",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "vault_id": {
+ "name": "vault_id",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "created_at": {
+ "name": "created_at",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": "CURRENT_TIMESTAMP"
+ }
+ },
+ "indexes": {
+ "story_encouragement_unique": {
+ "name": "story_encouragement_unique",
+ "columns": [
+ "story_id",
+ "vault_id"
+ ],
+ "isUnique": true
+ },
+ "story_encouragement_story_idx": {
+ "name": "story_encouragement_story_idx",
+ "columns": [
+ "story_id"
+ ],
+ "isUnique": false
+ }
+ },
+ "foreignKeys": {
+ "story_encouragements_story_id_public_stories_id_fk": {
+ "name": "story_encouragements_story_id_public_stories_id_fk",
+ "tableFrom": "story_encouragements",
+ "tableTo": "public_stories",
+ "columnsFrom": [
+ "story_id"
+ ],
+ "columnsTo": [
+ "id"
+ ],
+ "onDelete": "cascade",
+ "onUpdate": "no action"
+ },
+ "story_encouragements_vault_id_vaults_id_fk": {
+ "name": "story_encouragements_vault_id_vaults_id_fk",
+ "tableFrom": "story_encouragements",
+ "tableTo": "vaults",
+ "columnsFrom": [
+ "vault_id"
+ ],
+ "columnsTo": [
+ "id"
+ ],
+ "onDelete": "cascade",
+ "onUpdate": "no action"
+ }
+ },
+ "compositePrimaryKeys": {},
+ "uniqueConstraints": {},
+ "checkConstraints": {}
+ },
+ "story_reports": {
+ "name": "story_reports",
+ "columns": {
+ "id": {
+ "name": "id",
+ "type": "text",
+ "primaryKey": true,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "story_id": {
+ "name": "story_id",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "reporter_vault_id": {
+ "name": "reporter_vault_id",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "reason": {
+ "name": "reason",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "details": {
+ "name": "details",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": "''"
+ },
+ "status": {
+ "name": "status",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": "'open'"
+ },
+ "created_at": {
+ "name": "created_at",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": "CURRENT_TIMESTAMP"
+ },
+ "resolved_at": {
+ "name": "resolved_at",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": false,
+ "autoincrement": false
+ }
+ },
+ "indexes": {
+ "story_report_unique": {
+ "name": "story_report_unique",
+ "columns": [
+ "story_id",
+ "reporter_vault_id"
+ ],
+ "isUnique": true
+ },
+ "story_reports_status_idx": {
+ "name": "story_reports_status_idx",
+ "columns": [
+ "status"
+ ],
+ "isUnique": false
+ }
+ },
+ "foreignKeys": {
+ "story_reports_story_id_public_stories_id_fk": {
+ "name": "story_reports_story_id_public_stories_id_fk",
+ "tableFrom": "story_reports",
+ "tableTo": "public_stories",
+ "columnsFrom": [
+ "story_id"
+ ],
+ "columnsTo": [
+ "id"
+ ],
+ "onDelete": "cascade",
+ "onUpdate": "no action"
+ },
+ "story_reports_reporter_vault_id_vaults_id_fk": {
+ "name": "story_reports_reporter_vault_id_vaults_id_fk",
+ "tableFrom": "story_reports",
+ "tableTo": "vaults",
+ "columnsFrom": [
+ "reporter_vault_id"
+ ],
+ "columnsTo": [
+ "id"
+ ],
+ "onDelete": "cascade",
+ "onUpdate": "no action"
+ }
+ },
+ "compositePrimaryKeys": {},
+ "uniqueConstraints": {},
+ "checkConstraints": {}
+ },
+ "vaults": {
+ "name": "vaults",
+ "columns": {
+ "id": {
+ "name": "id",
+ "type": "text",
+ "primaryKey": true,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "recovery_hash": {
+ "name": "recovery_hash",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "alias": {
+ "name": "alias",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "region": {
+ "name": "region",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "pressure": {
+ "name": "pressure",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": "''"
+ },
+ "age_band": {
+ "name": "age_band",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": "''"
+ },
+ "gender": {
+ "name": "gender",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": "''"
+ },
+ "mbti": {
+ "name": "mbti",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": "''"
+ },
+ "zodiac": {
+ "name": "zodiac",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": "''"
+ },
+ "self_description": {
+ "name": "self_description",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": "''"
+ },
+ "repayment_plan": {
+ "name": "repayment_plan",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": "''"
+ },
+ "repayment_outlook": {
+ "name": "repayment_outlook",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": "''"
+ },
+ "income_plan": {
+ "name": "income_plan",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": "''"
+ },
+ "position_x": {
+ "name": "position_x",
+ "type": "real",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": 47
+ },
+ "position_y": {
+ "name": "position_y",
+ "type": "real",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": 63
+ },
+ "locale": {
+ "name": "locale",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": "'zh'"
+ },
+ "country_code": {
+ "name": "country_code",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": "''"
+ },
+ "country_name": {
+ "name": "country_name",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": "''"
+ },
+ "display_currency": {
+ "name": "display_currency",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": "'CNY'"
+ },
+ "monthly_income": {
+ "name": "monthly_income",
+ "type": "real",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": 0
+ },
+ "monthly_expenses": {
+ "name": "monthly_expenses",
+ "type": "real",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": 0
+ },
+ "discovery_consent": {
+ "name": "discovery_consent",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": false
+ },
+ "created_at": {
+ "name": "created_at",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": "CURRENT_TIMESTAMP"
+ },
+ "updated_at": {
+ "name": "updated_at",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": "CURRENT_TIMESTAMP"
+ }
+ },
+ "indexes": {
+ "vaults_recovery_hash_unique": {
+ "name": "vaults_recovery_hash_unique",
+ "columns": [
+ "recovery_hash"
+ ],
+ "isUnique": true
+ }
+ },
+ "foreignKeys": {},
+ "compositePrimaryKeys": {},
+ "uniqueConstraints": {},
+ "checkConstraints": {}
+ },
+ "world_category_candidates": {
+ "name": "world_category_candidates",
+ "columns": {
+ "id": {
+ "name": "id",
+ "type": "text",
+ "primaryKey": true,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "canonical_key": {
+ "name": "canonical_key",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "parent_kind": {
+ "name": "parent_kind",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": "'other'"
+ },
+ "name_zh": {
+ "name": "name_zh",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "name_en": {
+ "name": "name_en",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "description_zh": {
+ "name": "description_zh",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": "''"
+ },
+ "description_en": {
+ "name": "description_en",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": "''"
+ },
+ "status": {
+ "name": "status",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": "'candidate'"
+ },
+ "stage": {
+ "name": "stage",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": 0
+ },
+ "confidence": {
+ "name": "confidence",
+ "type": "real",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": 0
+ },
+ "unique_vaults": {
+ "name": "unique_vaults",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": 0
+ },
+ "region_count": {
+ "name": "region_count",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": 0
+ },
+ "mention_count": {
+ "name": "mention_count",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": 0
+ },
+ "emergence_score": {
+ "name": "emergence_score",
+ "type": "real",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": 0
+ },
+ "weight_profile_id": {
+ "name": "weight_profile_id",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": false,
+ "autoincrement": false
+ },
+ "merged_into_id": {
+ "name": "merged_into_id",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": false,
+ "autoincrement": false
+ },
+ "proposed_at": {
+ "name": "proposed_at",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": "CURRENT_TIMESTAMP"
+ },
+ "reviewed_at": {
+ "name": "reviewed_at",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": false,
+ "autoincrement": false
+ },
+ "published_at": {
+ "name": "published_at",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": false,
+ "autoincrement": false
+ },
+ "updated_at": {
+ "name": "updated_at",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": "CURRENT_TIMESTAMP"
+ }
+ },
+ "indexes": {
+ "world_category_candidates_canonical_key_unique": {
+ "name": "world_category_candidates_canonical_key_unique",
+ "columns": [
+ "canonical_key"
+ ],
+ "isUnique": true
+ },
+ "world_candidates_status_idx": {
+ "name": "world_candidates_status_idx",
+ "columns": [
+ "status"
+ ],
+ "isUnique": false
+ },
+ "world_candidates_score_idx": {
+ "name": "world_candidates_score_idx",
+ "columns": [
+ "emergence_score"
+ ],
+ "isUnique": false
+ }
+ },
+ "foreignKeys": {
+ "world_category_candidates_weight_profile_id_world_weight_profiles_id_fk": {
+ "name": "world_category_candidates_weight_profile_id_world_weight_profiles_id_fk",
+ "tableFrom": "world_category_candidates",
+ "tableTo": "world_weight_profiles",
+ "columnsFrom": [
+ "weight_profile_id"
+ ],
+ "columnsTo": [
+ "id"
+ ],
+ "onDelete": "no action",
+ "onUpdate": "no action"
+ }
+ },
+ "compositePrimaryKeys": {},
+ "uniqueConstraints": {},
+ "checkConstraints": {}
+ },
+ "world_growth_events": {
+ "name": "world_growth_events",
+ "columns": {
+ "id": {
+ "name": "id",
+ "type": "text",
+ "primaryKey": true,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "candidate_id": {
+ "name": "candidate_id",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "event_type": {
+ "name": "event_type",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "from_stage": {
+ "name": "from_stage",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": false,
+ "autoincrement": false
+ },
+ "to_stage": {
+ "name": "to_stage",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": false,
+ "autoincrement": false
+ },
+ "actor_type": {
+ "name": "actor_type",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": "'system'"
+ },
+ "weight_profile_id": {
+ "name": "weight_profile_id",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": false,
+ "autoincrement": false
+ },
+ "evidence_json": {
+ "name": "evidence_json",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": "'{}'"
+ },
+ "reason": {
+ "name": "reason",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": "''"
+ },
+ "created_at": {
+ "name": "created_at",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": "CURRENT_TIMESTAMP"
+ }
+ },
+ "indexes": {
+ "world_events_candidate_idx": {
+ "name": "world_events_candidate_idx",
+ "columns": [
+ "candidate_id"
+ ],
+ "isUnique": false
+ }
+ },
+ "foreignKeys": {
+ "world_growth_events_candidate_id_world_category_candidates_id_fk": {
+ "name": "world_growth_events_candidate_id_world_category_candidates_id_fk",
+ "tableFrom": "world_growth_events",
+ "tableTo": "world_category_candidates",
+ "columnsFrom": [
+ "candidate_id"
+ ],
+ "columnsTo": [
+ "id"
+ ],
+ "onDelete": "cascade",
+ "onUpdate": "no action"
+ },
+ "world_growth_events_weight_profile_id_world_weight_profiles_id_fk": {
+ "name": "world_growth_events_weight_profile_id_world_weight_profiles_id_fk",
+ "tableFrom": "world_growth_events",
+ "tableTo": "world_weight_profiles",
+ "columnsFrom": [
+ "weight_profile_id"
+ ],
+ "columnsTo": [
+ "id"
+ ],
+ "onDelete": "no action",
+ "onUpdate": "no action"
+ }
+ },
+ "compositePrimaryKeys": {},
+ "uniqueConstraints": {},
+ "checkConstraints": {}
+ },
+ "world_signal_assignments": {
+ "name": "world_signal_assignments",
+ "columns": {
+ "id": {
+ "name": "id",
+ "type": "text",
+ "primaryKey": true,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "vault_id": {
+ "name": "vault_id",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "debt_id": {
+ "name": "debt_id",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "candidate_id": {
+ "name": "candidate_id",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "confidence": {
+ "name": "confidence",
+ "type": "real",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "assignment_source": {
+ "name": "assignment_source",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": "'ai'"
+ },
+ "taxonomy_version": {
+ "name": "taxonomy_version",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": 1
+ },
+ "created_at": {
+ "name": "created_at",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": "CURRENT_TIMESTAMP"
+ },
+ "updated_at": {
+ "name": "updated_at",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": "CURRENT_TIMESTAMP"
+ }
+ },
+ "indexes": {
+ "world_signal_assignments_debt_id_unique": {
+ "name": "world_signal_assignments_debt_id_unique",
+ "columns": [
+ "debt_id"
+ ],
+ "isUnique": true
+ },
+ "world_signals_vault_idx": {
+ "name": "world_signals_vault_idx",
+ "columns": [
+ "vault_id"
+ ],
+ "isUnique": false
+ },
+ "world_signals_candidate_idx": {
+ "name": "world_signals_candidate_idx",
+ "columns": [
+ "candidate_id"
+ ],
+ "isUnique": false
+ }
+ },
+ "foreignKeys": {
+ "world_signal_assignments_vault_id_vaults_id_fk": {
+ "name": "world_signal_assignments_vault_id_vaults_id_fk",
+ "tableFrom": "world_signal_assignments",
+ "tableTo": "vaults",
+ "columnsFrom": [
+ "vault_id"
+ ],
+ "columnsTo": [
+ "id"
+ ],
+ "onDelete": "cascade",
+ "onUpdate": "no action"
+ },
+ "world_signal_assignments_debt_id_debts_id_fk": {
+ "name": "world_signal_assignments_debt_id_debts_id_fk",
+ "tableFrom": "world_signal_assignments",
+ "tableTo": "debts",
+ "columnsFrom": [
+ "debt_id"
+ ],
+ "columnsTo": [
+ "id"
+ ],
+ "onDelete": "cascade",
+ "onUpdate": "no action"
+ },
+ "world_signal_assignments_candidate_id_world_category_candidates_id_fk": {
+ "name": "world_signal_assignments_candidate_id_world_category_candidates_id_fk",
+ "tableFrom": "world_signal_assignments",
+ "tableTo": "world_category_candidates",
+ "columnsFrom": [
+ "candidate_id"
+ ],
+ "columnsTo": [
+ "id"
+ ],
+ "onDelete": "cascade",
+ "onUpdate": "no action"
+ }
+ },
+ "compositePrimaryKeys": {},
+ "uniqueConstraints": {},
+ "checkConstraints": {}
+ },
+ "world_weight_profiles": {
+ "name": "world_weight_profiles",
+ "columns": {
+ "id": {
+ "name": "id",
+ "type": "text",
+ "primaryKey": true,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "version": {
+ "name": "version",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "status": {
+ "name": "status",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": "'draft'"
+ },
+ "frequency_weight": {
+ "name": "frequency_weight",
+ "type": "real",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "growth_weight": {
+ "name": "growth_weight",
+ "type": "real",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "geography_weight": {
+ "name": "geography_weight",
+ "type": "real",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "recurrence_weight": {
+ "name": "recurrence_weight",
+ "type": "real",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "connection_weight": {
+ "name": "connection_weight",
+ "type": "real",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "quality_weight": {
+ "name": "quality_weight",
+ "type": "real",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "proposed_by": {
+ "name": "proposed_by",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": "'human'"
+ },
+ "model_ref": {
+ "name": "model_ref",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": false,
+ "autoincrement": false
+ },
+ "rationale": {
+ "name": "rationale",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": "''"
+ },
+ "created_at": {
+ "name": "created_at",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": "CURRENT_TIMESTAMP"
+ },
+ "activated_at": {
+ "name": "activated_at",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": false,
+ "autoincrement": false
+ }
+ },
+ "indexes": {
+ "world_weight_profiles_version_unique": {
+ "name": "world_weight_profiles_version_unique",
+ "columns": [
+ "version"
+ ],
+ "isUnique": true
+ }
+ },
+ "foreignKeys": {},
+ "compositePrimaryKeys": {},
+ "uniqueConstraints": {},
+ "checkConstraints": {}
+ }
+ },
+ "views": {},
+ "enums": {},
+ "_meta": {
+ "schemas": {},
+ "tables": {},
+ "columns": {}
+ },
+ "internal": {
+ "indexes": {}
+ }
+}
\ No newline at end of file
diff --git a/drizzle/meta/0014_snapshot.json b/drizzle/meta/0014_snapshot.json
new file mode 100644
index 0000000..b05c7e2
--- /dev/null
+++ b/drizzle/meta/0014_snapshot.json
@@ -0,0 +1,3010 @@
+{
+ "version": "6",
+ "dialect": "sqlite",
+ "id": "370226fd-3b9b-44e3-81bb-e48ff1ef1358",
+ "prevId": "a49d9d15-663c-4dbf-a688-e36d6280964a",
+ "tables": {
+ "account_auth_limits": {
+ "name": "account_auth_limits",
+ "columns": {
+ "limit_key": {
+ "name": "limit_key",
+ "type": "text",
+ "primaryKey": true,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "action": {
+ "name": "action",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "window_key": {
+ "name": "window_key",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "attempts": {
+ "name": "attempts",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": 0
+ },
+ "updated_at": {
+ "name": "updated_at",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": "CURRENT_TIMESTAMP"
+ }
+ },
+ "indexes": {
+ "account_auth_limits_window_idx": {
+ "name": "account_auth_limits_window_idx",
+ "columns": [
+ "window_key"
+ ],
+ "isUnique": false
+ }
+ },
+ "foreignKeys": {},
+ "compositePrimaryKeys": {},
+ "uniqueConstraints": {},
+ "checkConstraints": {}
+ },
+ "account_sessions": {
+ "name": "account_sessions",
+ "columns": {
+ "id": {
+ "name": "id",
+ "type": "text",
+ "primaryKey": true,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "account_id": {
+ "name": "account_id",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "token_hash": {
+ "name": "token_hash",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "expires_at": {
+ "name": "expires_at",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "created_at": {
+ "name": "created_at",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": "CURRENT_TIMESTAMP"
+ },
+ "last_seen_at": {
+ "name": "last_seen_at",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": "CURRENT_TIMESTAMP"
+ }
+ },
+ "indexes": {
+ "account_sessions_token_hash_unique": {
+ "name": "account_sessions_token_hash_unique",
+ "columns": [
+ "token_hash"
+ ],
+ "isUnique": true
+ },
+ "account_sessions_account_idx": {
+ "name": "account_sessions_account_idx",
+ "columns": [
+ "account_id"
+ ],
+ "isUnique": false
+ },
+ "account_sessions_expires_idx": {
+ "name": "account_sessions_expires_idx",
+ "columns": [
+ "expires_at"
+ ],
+ "isUnique": false
+ }
+ },
+ "foreignKeys": {
+ "account_sessions_account_id_accounts_id_fk": {
+ "name": "account_sessions_account_id_accounts_id_fk",
+ "tableFrom": "account_sessions",
+ "tableTo": "accounts",
+ "columnsFrom": [
+ "account_id"
+ ],
+ "columnsTo": [
+ "id"
+ ],
+ "onDelete": "cascade",
+ "onUpdate": "no action"
+ }
+ },
+ "compositePrimaryKeys": {},
+ "uniqueConstraints": {},
+ "checkConstraints": {}
+ },
+ "account_vaults": {
+ "name": "account_vaults",
+ "columns": {
+ "account_id": {
+ "name": "account_id",
+ "type": "text",
+ "primaryKey": true,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "vault_id": {
+ "name": "vault_id",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "linked_at": {
+ "name": "linked_at",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": "CURRENT_TIMESTAMP"
+ }
+ },
+ "indexes": {
+ "account_vaults_vault_id_unique": {
+ "name": "account_vaults_vault_id_unique",
+ "columns": [
+ "vault_id"
+ ],
+ "isUnique": true
+ },
+ "account_vaults_vault_idx": {
+ "name": "account_vaults_vault_idx",
+ "columns": [
+ "vault_id"
+ ],
+ "isUnique": false
+ }
+ },
+ "foreignKeys": {
+ "account_vaults_account_id_accounts_id_fk": {
+ "name": "account_vaults_account_id_accounts_id_fk",
+ "tableFrom": "account_vaults",
+ "tableTo": "accounts",
+ "columnsFrom": [
+ "account_id"
+ ],
+ "columnsTo": [
+ "id"
+ ],
+ "onDelete": "cascade",
+ "onUpdate": "no action"
+ },
+ "account_vaults_vault_id_vaults_id_fk": {
+ "name": "account_vaults_vault_id_vaults_id_fk",
+ "tableFrom": "account_vaults",
+ "tableTo": "vaults",
+ "columnsFrom": [
+ "vault_id"
+ ],
+ "columnsTo": [
+ "id"
+ ],
+ "onDelete": "cascade",
+ "onUpdate": "no action"
+ }
+ },
+ "compositePrimaryKeys": {},
+ "uniqueConstraints": {},
+ "checkConstraints": {}
+ },
+ "accounts": {
+ "name": "accounts",
+ "columns": {
+ "id": {
+ "name": "id",
+ "type": "text",
+ "primaryKey": true,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "user_code": {
+ "name": "user_code",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "username": {
+ "name": "username",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "username_normalized": {
+ "name": "username_normalized",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "password_hash": {
+ "name": "password_hash",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "password_salt": {
+ "name": "password_salt",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "password_iterations": {
+ "name": "password_iterations",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "status": {
+ "name": "status",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": "'active'"
+ },
+ "created_at": {
+ "name": "created_at",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": "CURRENT_TIMESTAMP"
+ },
+ "updated_at": {
+ "name": "updated_at",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": "CURRENT_TIMESTAMP"
+ },
+ "last_login_at": {
+ "name": "last_login_at",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": false,
+ "autoincrement": false
+ },
+ "last_seen_at": {
+ "name": "last_seen_at",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": false,
+ "autoincrement": false
+ }
+ },
+ "indexes": {
+ "accounts_user_code_unique": {
+ "name": "accounts_user_code_unique",
+ "columns": [
+ "user_code"
+ ],
+ "isUnique": true
+ },
+ "accounts_username_normalized_unique": {
+ "name": "accounts_username_normalized_unique",
+ "columns": [
+ "username_normalized"
+ ],
+ "isUnique": true
+ },
+ "accounts_created_idx": {
+ "name": "accounts_created_idx",
+ "columns": [
+ "created_at"
+ ],
+ "isUnique": false
+ }
+ },
+ "foreignKeys": {},
+ "compositePrimaryKeys": {},
+ "uniqueConstraints": {},
+ "checkConstraints": {}
+ },
+ "ai_daily_usage": {
+ "name": "ai_daily_usage",
+ "columns": {
+ "id": {
+ "name": "id",
+ "type": "text",
+ "primaryKey": true,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "vault_id": {
+ "name": "vault_id",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "usage_date": {
+ "name": "usage_date",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "request_count": {
+ "name": "request_count",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": 0
+ },
+ "input_tokens": {
+ "name": "input_tokens",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": 0
+ },
+ "output_tokens": {
+ "name": "output_tokens",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": 0
+ },
+ "updated_at": {
+ "name": "updated_at",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": "CURRENT_TIMESTAMP"
+ }
+ },
+ "indexes": {
+ "ai_daily_usage_vault_date_unique": {
+ "name": "ai_daily_usage_vault_date_unique",
+ "columns": [
+ "vault_id",
+ "usage_date"
+ ],
+ "isUnique": true
+ },
+ "ai_daily_usage_date_idx": {
+ "name": "ai_daily_usage_date_idx",
+ "columns": [
+ "usage_date"
+ ],
+ "isUnique": false
+ }
+ },
+ "foreignKeys": {
+ "ai_daily_usage_vault_id_vaults_id_fk": {
+ "name": "ai_daily_usage_vault_id_vaults_id_fk",
+ "tableFrom": "ai_daily_usage",
+ "tableTo": "vaults",
+ "columnsFrom": [
+ "vault_id"
+ ],
+ "columnsTo": [
+ "id"
+ ],
+ "onDelete": "cascade",
+ "onUpdate": "no action"
+ }
+ },
+ "compositePrimaryKeys": {},
+ "uniqueConstraints": {},
+ "checkConstraints": {}
+ },
+ "beta_enrollments": {
+ "name": "beta_enrollments",
+ "columns": {
+ "id": {
+ "name": "id",
+ "type": "text",
+ "primaryKey": true,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "vault_id": {
+ "name": "vault_id",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "invite_digest": {
+ "name": "invite_digest",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "consent_version": {
+ "name": "consent_version",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "created_at": {
+ "name": "created_at",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": "CURRENT_TIMESTAMP"
+ }
+ },
+ "indexes": {
+ "beta_enrollments_vault_id_unique": {
+ "name": "beta_enrollments_vault_id_unique",
+ "columns": [
+ "vault_id"
+ ],
+ "isUnique": true
+ },
+ "beta_enrollments_created_idx": {
+ "name": "beta_enrollments_created_idx",
+ "columns": [
+ "created_at"
+ ],
+ "isUnique": false
+ }
+ },
+ "foreignKeys": {
+ "beta_enrollments_vault_id_vaults_id_fk": {
+ "name": "beta_enrollments_vault_id_vaults_id_fk",
+ "tableFrom": "beta_enrollments",
+ "tableTo": "vaults",
+ "columnsFrom": [
+ "vault_id"
+ ],
+ "columnsTo": [
+ "id"
+ ],
+ "onDelete": "cascade",
+ "onUpdate": "no action"
+ }
+ },
+ "compositePrimaryKeys": {},
+ "uniqueConstraints": {},
+ "checkConstraints": {}
+ },
+ "beta_feedback": {
+ "name": "beta_feedback",
+ "columns": {
+ "id": {
+ "name": "id",
+ "type": "text",
+ "primaryKey": true,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "vault_id": {
+ "name": "vault_id",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "category": {
+ "name": "category",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "rating": {
+ "name": "rating",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "message": {
+ "name": "message",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "page_path": {
+ "name": "page_path",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": "'/'"
+ },
+ "status": {
+ "name": "status",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": "'open'"
+ },
+ "created_at": {
+ "name": "created_at",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": "CURRENT_TIMESTAMP"
+ },
+ "resolved_at": {
+ "name": "resolved_at",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": false,
+ "autoincrement": false
+ }
+ },
+ "indexes": {
+ "beta_feedback_vault_idx": {
+ "name": "beta_feedback_vault_idx",
+ "columns": [
+ "vault_id"
+ ],
+ "isUnique": false
+ },
+ "beta_feedback_status_idx": {
+ "name": "beta_feedback_status_idx",
+ "columns": [
+ "status"
+ ],
+ "isUnique": false
+ }
+ },
+ "foreignKeys": {
+ "beta_feedback_vault_id_vaults_id_fk": {
+ "name": "beta_feedback_vault_id_vaults_id_fk",
+ "tableFrom": "beta_feedback",
+ "tableTo": "vaults",
+ "columnsFrom": [
+ "vault_id"
+ ],
+ "columnsTo": [
+ "id"
+ ],
+ "onDelete": "cascade",
+ "onUpdate": "no action"
+ }
+ },
+ "compositePrimaryKeys": {},
+ "uniqueConstraints": {},
+ "checkConstraints": {}
+ },
+ "beta_invite_counters": {
+ "name": "beta_invite_counters",
+ "columns": {
+ "invite_digest": {
+ "name": "invite_digest",
+ "type": "text",
+ "primaryKey": true,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "uses": {
+ "name": "uses",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": 0
+ },
+ "max_uses": {
+ "name": "max_uses",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "updated_at": {
+ "name": "updated_at",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": "CURRENT_TIMESTAMP"
+ }
+ },
+ "indexes": {},
+ "foreignKeys": {},
+ "compositePrimaryKeys": {},
+ "uniqueConstraints": {},
+ "checkConstraints": {}
+ },
+ "beta_runtime_settings": {
+ "name": "beta_runtime_settings",
+ "columns": {
+ "id": {
+ "name": "id",
+ "type": "text",
+ "primaryKey": true,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "signups_enabled": {
+ "name": "signups_enabled",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "updated_by_digest": {
+ "name": "updated_by_digest",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": false,
+ "autoincrement": false
+ },
+ "updated_at": {
+ "name": "updated_at",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": "CURRENT_TIMESTAMP"
+ }
+ },
+ "indexes": {},
+ "foreignKeys": {},
+ "compositePrimaryKeys": {},
+ "uniqueConstraints": {},
+ "checkConstraints": {}
+ },
+ "community_moderation_actions": {
+ "name": "community_moderation_actions",
+ "columns": {
+ "id": {
+ "name": "id",
+ "type": "text",
+ "primaryKey": true,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "story_id": {
+ "name": "story_id",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "actor_digest": {
+ "name": "actor_digest",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "action": {
+ "name": "action",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "from_status": {
+ "name": "from_status",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "to_status": {
+ "name": "to_status",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "note": {
+ "name": "note",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": "''"
+ },
+ "created_at": {
+ "name": "created_at",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": "CURRENT_TIMESTAMP"
+ }
+ },
+ "indexes": {
+ "community_moderation_story_idx": {
+ "name": "community_moderation_story_idx",
+ "columns": [
+ "story_id"
+ ],
+ "isUnique": false
+ },
+ "community_moderation_created_idx": {
+ "name": "community_moderation_created_idx",
+ "columns": [
+ "created_at"
+ ],
+ "isUnique": false
+ }
+ },
+ "foreignKeys": {
+ "community_moderation_actions_story_id_public_stories_id_fk": {
+ "name": "community_moderation_actions_story_id_public_stories_id_fk",
+ "tableFrom": "community_moderation_actions",
+ "tableTo": "public_stories",
+ "columnsFrom": [
+ "story_id"
+ ],
+ "columnsTo": [
+ "id"
+ ],
+ "onDelete": "cascade",
+ "onUpdate": "no action"
+ }
+ },
+ "compositePrimaryKeys": {},
+ "uniqueConstraints": {},
+ "checkConstraints": {}
+ },
+ "community_rate_limits": {
+ "name": "community_rate_limits",
+ "columns": {
+ "id": {
+ "name": "id",
+ "type": "text",
+ "primaryKey": true,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "vault_id": {
+ "name": "vault_id",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "action": {
+ "name": "action",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "window_key": {
+ "name": "window_key",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "count": {
+ "name": "count",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": 0
+ },
+ "updated_at": {
+ "name": "updated_at",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": "CURRENT_TIMESTAMP"
+ }
+ },
+ "indexes": {
+ "community_rate_vault_action_window_unique": {
+ "name": "community_rate_vault_action_window_unique",
+ "columns": [
+ "vault_id",
+ "action",
+ "window_key"
+ ],
+ "isUnique": true
+ },
+ "community_rate_window_idx": {
+ "name": "community_rate_window_idx",
+ "columns": [
+ "window_key"
+ ],
+ "isUnique": false
+ }
+ },
+ "foreignKeys": {
+ "community_rate_limits_vault_id_vaults_id_fk": {
+ "name": "community_rate_limits_vault_id_vaults_id_fk",
+ "tableFrom": "community_rate_limits",
+ "tableTo": "vaults",
+ "columnsFrom": [
+ "vault_id"
+ ],
+ "columnsTo": [
+ "id"
+ ],
+ "onDelete": "cascade",
+ "onUpdate": "no action"
+ }
+ },
+ "compositePrimaryKeys": {},
+ "uniqueConstraints": {},
+ "checkConstraints": {}
+ },
+ "debts": {
+ "name": "debts",
+ "columns": {
+ "id": {
+ "name": "id",
+ "type": "text",
+ "primaryKey": true,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "vault_id": {
+ "name": "vault_id",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "kind": {
+ "name": "kind",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "custom_label": {
+ "name": "custom_label",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": false,
+ "autoincrement": false
+ },
+ "currency": {
+ "name": "currency",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "original": {
+ "name": "original",
+ "type": "real",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "balance": {
+ "name": "balance",
+ "type": "real",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "monthly": {
+ "name": "monthly",
+ "type": "real",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "apr": {
+ "name": "apr",
+ "type": "real",
+ "primaryKey": false,
+ "notNull": false,
+ "autoincrement": false
+ },
+ "minimum_payment": {
+ "name": "minimum_payment",
+ "type": "real",
+ "primaryKey": false,
+ "notNull": false,
+ "autoincrement": false
+ },
+ "payment_status": {
+ "name": "payment_status",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": "'unknown'"
+ },
+ "remaining_months": {
+ "name": "remaining_months",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": false,
+ "autoincrement": false
+ },
+ "due_day": {
+ "name": "due_day",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "method": {
+ "name": "method",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "sharing_mode": {
+ "name": "sharing_mode",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": "'private'"
+ },
+ "last_paid_at": {
+ "name": "last_paid_at",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": false,
+ "autoincrement": false
+ },
+ "payments": {
+ "name": "payments",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": 0
+ },
+ "created_at": {
+ "name": "created_at",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": "CURRENT_TIMESTAMP"
+ },
+ "updated_at": {
+ "name": "updated_at",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": "CURRENT_TIMESTAMP"
+ }
+ },
+ "indexes": {
+ "debts_vault_id_idx": {
+ "name": "debts_vault_id_idx",
+ "columns": [
+ "vault_id"
+ ],
+ "isUnique": false
+ }
+ },
+ "foreignKeys": {
+ "debts_vault_id_vaults_id_fk": {
+ "name": "debts_vault_id_vaults_id_fk",
+ "tableFrom": "debts",
+ "tableTo": "vaults",
+ "columnsFrom": [
+ "vault_id"
+ ],
+ "columnsTo": [
+ "id"
+ ],
+ "onDelete": "cascade",
+ "onUpdate": "no action"
+ }
+ },
+ "compositePrimaryKeys": {},
+ "uniqueConstraints": {},
+ "checkConstraints": {}
+ },
+ "lucky_income_claims": {
+ "name": "lucky_income_claims",
+ "columns": {
+ "id": {
+ "name": "id",
+ "type": "text",
+ "primaryKey": true,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "vault_id": {
+ "name": "vault_id",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "event_date": {
+ "name": "event_date",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "created_at": {
+ "name": "created_at",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": "CURRENT_TIMESTAMP"
+ }
+ },
+ "indexes": {
+ "lucky_income_vault_day_unique": {
+ "name": "lucky_income_vault_day_unique",
+ "columns": [
+ "vault_id",
+ "event_date"
+ ],
+ "isUnique": true
+ }
+ },
+ "foreignKeys": {
+ "lucky_income_claims_vault_id_vaults_id_fk": {
+ "name": "lucky_income_claims_vault_id_vaults_id_fk",
+ "tableFrom": "lucky_income_claims",
+ "tableTo": "vaults",
+ "columnsFrom": [
+ "vault_id"
+ ],
+ "columnsTo": [
+ "id"
+ ],
+ "onDelete": "cascade",
+ "onUpdate": "no action"
+ }
+ },
+ "compositePrimaryKeys": {},
+ "uniqueConstraints": {},
+ "checkConstraints": {}
+ },
+ "owner_admins": {
+ "name": "owner_admins",
+ "columns": {
+ "id": {
+ "name": "id",
+ "type": "text",
+ "primaryKey": true,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "email_digest": {
+ "name": "email_digest",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "role": {
+ "name": "role",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": "'owner'"
+ },
+ "activated_at": {
+ "name": "activated_at",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": "CURRENT_TIMESTAMP"
+ },
+ "last_seen_at": {
+ "name": "last_seen_at",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": "CURRENT_TIMESTAMP"
+ }
+ },
+ "indexes": {
+ "owner_admins_email_digest_unique": {
+ "name": "owner_admins_email_digest_unique",
+ "columns": [
+ "email_digest"
+ ],
+ "isUnique": true
+ }
+ },
+ "foreignKeys": {},
+ "compositePrimaryKeys": {},
+ "uniqueConstraints": {},
+ "checkConstraints": {}
+ },
+ "payment_records": {
+ "name": "payment_records",
+ "columns": {
+ "id": {
+ "name": "id",
+ "type": "text",
+ "primaryKey": true,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "vault_id": {
+ "name": "vault_id",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "debt_id": {
+ "name": "debt_id",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "scheduled_date": {
+ "name": "scheduled_date",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": false,
+ "autoincrement": false
+ },
+ "confirmed_at": {
+ "name": "confirmed_at",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "event_date": {
+ "name": "event_date",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": false,
+ "autoincrement": false
+ },
+ "cash_payment": {
+ "name": "cash_payment",
+ "type": "real",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "new_balance": {
+ "name": "new_balance",
+ "type": "real",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "source": {
+ "name": "source",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": "'self_report'"
+ },
+ "income_type": {
+ "name": "income_type",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": false,
+ "autoincrement": false
+ },
+ "created_at": {
+ "name": "created_at",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": "CURRENT_TIMESTAMP"
+ }
+ },
+ "indexes": {
+ "payments_vault_id_idx": {
+ "name": "payments_vault_id_idx",
+ "columns": [
+ "vault_id"
+ ],
+ "isUnique": false
+ },
+ "payments_debt_id_idx": {
+ "name": "payments_debt_id_idx",
+ "columns": [
+ "debt_id"
+ ],
+ "isUnique": false
+ }
+ },
+ "foreignKeys": {
+ "payment_records_vault_id_vaults_id_fk": {
+ "name": "payment_records_vault_id_vaults_id_fk",
+ "tableFrom": "payment_records",
+ "tableTo": "vaults",
+ "columnsFrom": [
+ "vault_id"
+ ],
+ "columnsTo": [
+ "id"
+ ],
+ "onDelete": "cascade",
+ "onUpdate": "no action"
+ },
+ "payment_records_debt_id_debts_id_fk": {
+ "name": "payment_records_debt_id_debts_id_fk",
+ "tableFrom": "payment_records",
+ "tableTo": "debts",
+ "columnsFrom": [
+ "debt_id"
+ ],
+ "columnsTo": [
+ "id"
+ ],
+ "onDelete": "cascade",
+ "onUpdate": "no action"
+ }
+ },
+ "compositePrimaryKeys": {},
+ "uniqueConstraints": {},
+ "checkConstraints": {}
+ },
+ "policy_acceptances": {
+ "name": "policy_acceptances",
+ "columns": {
+ "id": {
+ "name": "id",
+ "type": "text",
+ "primaryKey": true,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "vault_id": {
+ "name": "vault_id",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "policy_key": {
+ "name": "policy_key",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "policy_version": {
+ "name": "policy_version",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "accepted_at": {
+ "name": "accepted_at",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": "CURRENT_TIMESTAMP"
+ }
+ },
+ "indexes": {
+ "policy_acceptance_vault_key_version_unique": {
+ "name": "policy_acceptance_vault_key_version_unique",
+ "columns": [
+ "vault_id",
+ "policy_key",
+ "policy_version"
+ ],
+ "isUnique": true
+ },
+ "policy_acceptance_vault_idx": {
+ "name": "policy_acceptance_vault_idx",
+ "columns": [
+ "vault_id"
+ ],
+ "isUnique": false
+ }
+ },
+ "foreignKeys": {
+ "policy_acceptances_vault_id_vaults_id_fk": {
+ "name": "policy_acceptances_vault_id_vaults_id_fk",
+ "tableFrom": "policy_acceptances",
+ "tableTo": "vaults",
+ "columnsFrom": [
+ "vault_id"
+ ],
+ "columnsTo": [
+ "id"
+ ],
+ "onDelete": "cascade",
+ "onUpdate": "no action"
+ }
+ },
+ "compositePrimaryKeys": {},
+ "uniqueConstraints": {},
+ "checkConstraints": {}
+ },
+ "public_stories": {
+ "name": "public_stories",
+ "columns": {
+ "id": {
+ "name": "id",
+ "type": "text",
+ "primaryKey": true,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "vault_id": {
+ "name": "vault_id",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "debt_id": {
+ "name": "debt_id",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "anonymous_name": {
+ "name": "anonymous_name",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "country_code": {
+ "name": "country_code",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": "''"
+ },
+ "debt_kind": {
+ "name": "debt_kind",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "amount_band": {
+ "name": "amount_band",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "currency": {
+ "name": "currency",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "repayment_approach": {
+ "name": "repayment_approach",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": "'other'"
+ },
+ "story_text": {
+ "name": "story_text",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "status": {
+ "name": "status",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": "'pending'"
+ },
+ "created_at": {
+ "name": "created_at",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": "CURRENT_TIMESTAMP"
+ },
+ "updated_at": {
+ "name": "updated_at",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": "CURRENT_TIMESTAMP"
+ }
+ },
+ "indexes": {
+ "public_stories_status_idx": {
+ "name": "public_stories_status_idx",
+ "columns": [
+ "status"
+ ],
+ "isUnique": false
+ },
+ "public_stories_vault_idx": {
+ "name": "public_stories_vault_idx",
+ "columns": [
+ "vault_id"
+ ],
+ "isUnique": false
+ }
+ },
+ "foreignKeys": {
+ "public_stories_vault_id_vaults_id_fk": {
+ "name": "public_stories_vault_id_vaults_id_fk",
+ "tableFrom": "public_stories",
+ "tableTo": "vaults",
+ "columnsFrom": [
+ "vault_id"
+ ],
+ "columnsTo": [
+ "id"
+ ],
+ "onDelete": "cascade",
+ "onUpdate": "no action"
+ },
+ "public_stories_debt_id_debts_id_fk": {
+ "name": "public_stories_debt_id_debts_id_fk",
+ "tableFrom": "public_stories",
+ "tableTo": "debts",
+ "columnsFrom": [
+ "debt_id"
+ ],
+ "columnsTo": [
+ "id"
+ ],
+ "onDelete": "cascade",
+ "onUpdate": "no action"
+ }
+ },
+ "compositePrimaryKeys": {},
+ "uniqueConstraints": {},
+ "checkConstraints": {}
+ },
+ "referral_codes": {
+ "name": "referral_codes",
+ "columns": {
+ "id": {
+ "name": "id",
+ "type": "text",
+ "primaryKey": true,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "vault_id": {
+ "name": "vault_id",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "code": {
+ "name": "code",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "status": {
+ "name": "status",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": "'active'"
+ },
+ "created_at": {
+ "name": "created_at",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": "CURRENT_TIMESTAMP"
+ }
+ },
+ "indexes": {
+ "referral_codes_vault_id_unique": {
+ "name": "referral_codes_vault_id_unique",
+ "columns": [
+ "vault_id"
+ ],
+ "isUnique": true
+ },
+ "referral_codes_code_unique": {
+ "name": "referral_codes_code_unique",
+ "columns": [
+ "code"
+ ],
+ "isUnique": true
+ },
+ "referral_codes_status_idx": {
+ "name": "referral_codes_status_idx",
+ "columns": [
+ "status"
+ ],
+ "isUnique": false
+ }
+ },
+ "foreignKeys": {
+ "referral_codes_vault_id_vaults_id_fk": {
+ "name": "referral_codes_vault_id_vaults_id_fk",
+ "tableFrom": "referral_codes",
+ "tableTo": "vaults",
+ "columnsFrom": [
+ "vault_id"
+ ],
+ "columnsTo": [
+ "id"
+ ],
+ "onDelete": "cascade",
+ "onUpdate": "no action"
+ }
+ },
+ "compositePrimaryKeys": {},
+ "uniqueConstraints": {},
+ "checkConstraints": {}
+ },
+ "referral_relationships": {
+ "name": "referral_relationships",
+ "columns": {
+ "id": {
+ "name": "id",
+ "type": "text",
+ "primaryKey": true,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "inviter_vault_id": {
+ "name": "inviter_vault_id",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "invited_vault_id": {
+ "name": "invited_vault_id",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "code_id": {
+ "name": "code_id",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "status": {
+ "name": "status",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": "'pending'"
+ },
+ "qualified_at": {
+ "name": "qualified_at",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": false,
+ "autoincrement": false
+ },
+ "rewarded_at": {
+ "name": "rewarded_at",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": false,
+ "autoincrement": false
+ },
+ "created_at": {
+ "name": "created_at",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": "CURRENT_TIMESTAMP"
+ }
+ },
+ "indexes": {
+ "referral_relationships_invited_vault_id_unique": {
+ "name": "referral_relationships_invited_vault_id_unique",
+ "columns": [
+ "invited_vault_id"
+ ],
+ "isUnique": true
+ },
+ "referrals_inviter_status_idx": {
+ "name": "referrals_inviter_status_idx",
+ "columns": [
+ "inviter_vault_id",
+ "status"
+ ],
+ "isUnique": false
+ },
+ "referrals_created_idx": {
+ "name": "referrals_created_idx",
+ "columns": [
+ "created_at"
+ ],
+ "isUnique": false
+ }
+ },
+ "foreignKeys": {
+ "referral_relationships_inviter_vault_id_vaults_id_fk": {
+ "name": "referral_relationships_inviter_vault_id_vaults_id_fk",
+ "tableFrom": "referral_relationships",
+ "tableTo": "vaults",
+ "columnsFrom": [
+ "inviter_vault_id"
+ ],
+ "columnsTo": [
+ "id"
+ ],
+ "onDelete": "cascade",
+ "onUpdate": "no action"
+ },
+ "referral_relationships_invited_vault_id_vaults_id_fk": {
+ "name": "referral_relationships_invited_vault_id_vaults_id_fk",
+ "tableFrom": "referral_relationships",
+ "tableTo": "vaults",
+ "columnsFrom": [
+ "invited_vault_id"
+ ],
+ "columnsTo": [
+ "id"
+ ],
+ "onDelete": "cascade",
+ "onUpdate": "no action"
+ },
+ "referral_relationships_code_id_referral_codes_id_fk": {
+ "name": "referral_relationships_code_id_referral_codes_id_fk",
+ "tableFrom": "referral_relationships",
+ "tableTo": "referral_codes",
+ "columnsFrom": [
+ "code_id"
+ ],
+ "columnsTo": [
+ "id"
+ ],
+ "onDelete": "cascade",
+ "onUpdate": "no action"
+ }
+ },
+ "compositePrimaryKeys": {},
+ "uniqueConstraints": {},
+ "checkConstraints": {}
+ },
+ "shore_value_ledger": {
+ "name": "shore_value_ledger",
+ "columns": {
+ "id": {
+ "name": "id",
+ "type": "text",
+ "primaryKey": true,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "vault_id": {
+ "name": "vault_id",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "event_key": {
+ "name": "event_key",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "event_type": {
+ "name": "event_type",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "points": {
+ "name": "points",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "reference_id": {
+ "name": "reference_id",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": false,
+ "autoincrement": false
+ },
+ "created_at": {
+ "name": "created_at",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": "CURRENT_TIMESTAMP"
+ }
+ },
+ "indexes": {
+ "shore_value_ledger_event_key_unique": {
+ "name": "shore_value_ledger_event_key_unique",
+ "columns": [
+ "event_key"
+ ],
+ "isUnique": true
+ },
+ "shore_value_vault_created_idx": {
+ "name": "shore_value_vault_created_idx",
+ "columns": [
+ "vault_id",
+ "created_at"
+ ],
+ "isUnique": false
+ },
+ "shore_value_event_type_idx": {
+ "name": "shore_value_event_type_idx",
+ "columns": [
+ "event_type"
+ ],
+ "isUnique": false
+ }
+ },
+ "foreignKeys": {
+ "shore_value_ledger_vault_id_vaults_id_fk": {
+ "name": "shore_value_ledger_vault_id_vaults_id_fk",
+ "tableFrom": "shore_value_ledger",
+ "tableTo": "vaults",
+ "columnsFrom": [
+ "vault_id"
+ ],
+ "columnsTo": [
+ "id"
+ ],
+ "onDelete": "cascade",
+ "onUpdate": "no action"
+ }
+ },
+ "compositePrimaryKeys": {},
+ "uniqueConstraints": {},
+ "checkConstraints": {}
+ },
+ "starlight_gifts": {
+ "name": "starlight_gifts",
+ "columns": {
+ "id": {
+ "name": "id",
+ "type": "text",
+ "primaryKey": true,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "sender_vault_id": {
+ "name": "sender_vault_id",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "recipient_vault_id": {
+ "name": "recipient_vault_id",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "story_id": {
+ "name": "story_id",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": false,
+ "autoincrement": false
+ },
+ "points": {
+ "name": "points",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "gift_date": {
+ "name": "gift_date",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "idempotency_key": {
+ "name": "idempotency_key",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "created_at": {
+ "name": "created_at",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": "CURRENT_TIMESTAMP"
+ }
+ },
+ "indexes": {
+ "starlight_gifts_idempotency_key_unique": {
+ "name": "starlight_gifts_idempotency_key_unique",
+ "columns": [
+ "idempotency_key"
+ ],
+ "isUnique": true
+ },
+ "starlight_sender_created_idx": {
+ "name": "starlight_sender_created_idx",
+ "columns": [
+ "sender_vault_id",
+ "created_at"
+ ],
+ "isUnique": false
+ },
+ "starlight_recipient_created_idx": {
+ "name": "starlight_recipient_created_idx",
+ "columns": [
+ "recipient_vault_id",
+ "created_at"
+ ],
+ "isUnique": false
+ }
+ },
+ "foreignKeys": {
+ "starlight_gifts_sender_vault_id_vaults_id_fk": {
+ "name": "starlight_gifts_sender_vault_id_vaults_id_fk",
+ "tableFrom": "starlight_gifts",
+ "tableTo": "vaults",
+ "columnsFrom": [
+ "sender_vault_id"
+ ],
+ "columnsTo": [
+ "id"
+ ],
+ "onDelete": "cascade",
+ "onUpdate": "no action"
+ },
+ "starlight_gifts_recipient_vault_id_vaults_id_fk": {
+ "name": "starlight_gifts_recipient_vault_id_vaults_id_fk",
+ "tableFrom": "starlight_gifts",
+ "tableTo": "vaults",
+ "columnsFrom": [
+ "recipient_vault_id"
+ ],
+ "columnsTo": [
+ "id"
+ ],
+ "onDelete": "cascade",
+ "onUpdate": "no action"
+ }
+ },
+ "compositePrimaryKeys": {},
+ "uniqueConstraints": {},
+ "checkConstraints": {}
+ },
+ "starlight_wallets": {
+ "name": "starlight_wallets",
+ "columns": {
+ "vault_id": {
+ "name": "vault_id",
+ "type": "text",
+ "primaryKey": true,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "available": {
+ "name": "available",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": 0
+ },
+ "lifetime_earned": {
+ "name": "lifetime_earned",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": 0
+ },
+ "lifetime_sent": {
+ "name": "lifetime_sent",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": 0
+ },
+ "lifetime_received": {
+ "name": "lifetime_received",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": 0
+ },
+ "updated_at": {
+ "name": "updated_at",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": "CURRENT_TIMESTAMP"
+ }
+ },
+ "indexes": {},
+ "foreignKeys": {
+ "starlight_wallets_vault_id_vaults_id_fk": {
+ "name": "starlight_wallets_vault_id_vaults_id_fk",
+ "tableFrom": "starlight_wallets",
+ "tableTo": "vaults",
+ "columnsFrom": [
+ "vault_id"
+ ],
+ "columnsTo": [
+ "id"
+ ],
+ "onDelete": "cascade",
+ "onUpdate": "no action"
+ }
+ },
+ "compositePrimaryKeys": {},
+ "uniqueConstraints": {},
+ "checkConstraints": {}
+ },
+ "story_encouragements": {
+ "name": "story_encouragements",
+ "columns": {
+ "id": {
+ "name": "id",
+ "type": "text",
+ "primaryKey": true,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "story_id": {
+ "name": "story_id",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "vault_id": {
+ "name": "vault_id",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "created_at": {
+ "name": "created_at",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": "CURRENT_TIMESTAMP"
+ }
+ },
+ "indexes": {
+ "story_encouragement_unique": {
+ "name": "story_encouragement_unique",
+ "columns": [
+ "story_id",
+ "vault_id"
+ ],
+ "isUnique": true
+ },
+ "story_encouragement_story_idx": {
+ "name": "story_encouragement_story_idx",
+ "columns": [
+ "story_id"
+ ],
+ "isUnique": false
+ }
+ },
+ "foreignKeys": {
+ "story_encouragements_story_id_public_stories_id_fk": {
+ "name": "story_encouragements_story_id_public_stories_id_fk",
+ "tableFrom": "story_encouragements",
+ "tableTo": "public_stories",
+ "columnsFrom": [
+ "story_id"
+ ],
+ "columnsTo": [
+ "id"
+ ],
+ "onDelete": "cascade",
+ "onUpdate": "no action"
+ },
+ "story_encouragements_vault_id_vaults_id_fk": {
+ "name": "story_encouragements_vault_id_vaults_id_fk",
+ "tableFrom": "story_encouragements",
+ "tableTo": "vaults",
+ "columnsFrom": [
+ "vault_id"
+ ],
+ "columnsTo": [
+ "id"
+ ],
+ "onDelete": "cascade",
+ "onUpdate": "no action"
+ }
+ },
+ "compositePrimaryKeys": {},
+ "uniqueConstraints": {},
+ "checkConstraints": {}
+ },
+ "story_reports": {
+ "name": "story_reports",
+ "columns": {
+ "id": {
+ "name": "id",
+ "type": "text",
+ "primaryKey": true,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "story_id": {
+ "name": "story_id",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "reporter_vault_id": {
+ "name": "reporter_vault_id",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "reason": {
+ "name": "reason",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "details": {
+ "name": "details",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": "''"
+ },
+ "status": {
+ "name": "status",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": "'open'"
+ },
+ "created_at": {
+ "name": "created_at",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": "CURRENT_TIMESTAMP"
+ },
+ "resolved_at": {
+ "name": "resolved_at",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": false,
+ "autoincrement": false
+ }
+ },
+ "indexes": {
+ "story_report_unique": {
+ "name": "story_report_unique",
+ "columns": [
+ "story_id",
+ "reporter_vault_id"
+ ],
+ "isUnique": true
+ },
+ "story_reports_status_idx": {
+ "name": "story_reports_status_idx",
+ "columns": [
+ "status"
+ ],
+ "isUnique": false
+ }
+ },
+ "foreignKeys": {
+ "story_reports_story_id_public_stories_id_fk": {
+ "name": "story_reports_story_id_public_stories_id_fk",
+ "tableFrom": "story_reports",
+ "tableTo": "public_stories",
+ "columnsFrom": [
+ "story_id"
+ ],
+ "columnsTo": [
+ "id"
+ ],
+ "onDelete": "cascade",
+ "onUpdate": "no action"
+ },
+ "story_reports_reporter_vault_id_vaults_id_fk": {
+ "name": "story_reports_reporter_vault_id_vaults_id_fk",
+ "tableFrom": "story_reports",
+ "tableTo": "vaults",
+ "columnsFrom": [
+ "reporter_vault_id"
+ ],
+ "columnsTo": [
+ "id"
+ ],
+ "onDelete": "cascade",
+ "onUpdate": "no action"
+ }
+ },
+ "compositePrimaryKeys": {},
+ "uniqueConstraints": {},
+ "checkConstraints": {}
+ },
+ "vaults": {
+ "name": "vaults",
+ "columns": {
+ "id": {
+ "name": "id",
+ "type": "text",
+ "primaryKey": true,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "recovery_hash": {
+ "name": "recovery_hash",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "alias": {
+ "name": "alias",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "region": {
+ "name": "region",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "pressure": {
+ "name": "pressure",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": "''"
+ },
+ "age_band": {
+ "name": "age_band",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": "''"
+ },
+ "gender": {
+ "name": "gender",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": "''"
+ },
+ "mbti": {
+ "name": "mbti",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": "''"
+ },
+ "zodiac": {
+ "name": "zodiac",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": "''"
+ },
+ "self_description": {
+ "name": "self_description",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": "''"
+ },
+ "repayment_plan": {
+ "name": "repayment_plan",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": "''"
+ },
+ "repayment_outlook": {
+ "name": "repayment_outlook",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": "''"
+ },
+ "income_plan": {
+ "name": "income_plan",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": "''"
+ },
+ "position_x": {
+ "name": "position_x",
+ "type": "real",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": 47
+ },
+ "position_y": {
+ "name": "position_y",
+ "type": "real",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": 63
+ },
+ "locale": {
+ "name": "locale",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": "'zh'"
+ },
+ "country_code": {
+ "name": "country_code",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": "''"
+ },
+ "country_name": {
+ "name": "country_name",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": "''"
+ },
+ "display_currency": {
+ "name": "display_currency",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": "'CNY'"
+ },
+ "monthly_income": {
+ "name": "monthly_income",
+ "type": "real",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": 0
+ },
+ "monthly_expenses": {
+ "name": "monthly_expenses",
+ "type": "real",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": 0
+ },
+ "discovery_consent": {
+ "name": "discovery_consent",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": false
+ },
+ "created_at": {
+ "name": "created_at",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": "CURRENT_TIMESTAMP"
+ },
+ "updated_at": {
+ "name": "updated_at",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": "CURRENT_TIMESTAMP"
+ }
+ },
+ "indexes": {
+ "vaults_recovery_hash_unique": {
+ "name": "vaults_recovery_hash_unique",
+ "columns": [
+ "recovery_hash"
+ ],
+ "isUnique": true
+ }
+ },
+ "foreignKeys": {},
+ "compositePrimaryKeys": {},
+ "uniqueConstraints": {},
+ "checkConstraints": {}
+ },
+ "world_category_candidates": {
+ "name": "world_category_candidates",
+ "columns": {
+ "id": {
+ "name": "id",
+ "type": "text",
+ "primaryKey": true,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "canonical_key": {
+ "name": "canonical_key",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "parent_kind": {
+ "name": "parent_kind",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": "'other'"
+ },
+ "name_zh": {
+ "name": "name_zh",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "name_en": {
+ "name": "name_en",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "description_zh": {
+ "name": "description_zh",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": "''"
+ },
+ "description_en": {
+ "name": "description_en",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": "''"
+ },
+ "status": {
+ "name": "status",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": "'candidate'"
+ },
+ "stage": {
+ "name": "stage",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": 0
+ },
+ "confidence": {
+ "name": "confidence",
+ "type": "real",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": 0
+ },
+ "unique_vaults": {
+ "name": "unique_vaults",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": 0
+ },
+ "region_count": {
+ "name": "region_count",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": 0
+ },
+ "mention_count": {
+ "name": "mention_count",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": 0
+ },
+ "emergence_score": {
+ "name": "emergence_score",
+ "type": "real",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": 0
+ },
+ "weight_profile_id": {
+ "name": "weight_profile_id",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": false,
+ "autoincrement": false
+ },
+ "merged_into_id": {
+ "name": "merged_into_id",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": false,
+ "autoincrement": false
+ },
+ "proposed_at": {
+ "name": "proposed_at",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": "CURRENT_TIMESTAMP"
+ },
+ "reviewed_at": {
+ "name": "reviewed_at",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": false,
+ "autoincrement": false
+ },
+ "published_at": {
+ "name": "published_at",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": false,
+ "autoincrement": false
+ },
+ "updated_at": {
+ "name": "updated_at",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": "CURRENT_TIMESTAMP"
+ }
+ },
+ "indexes": {
+ "world_category_candidates_canonical_key_unique": {
+ "name": "world_category_candidates_canonical_key_unique",
+ "columns": [
+ "canonical_key"
+ ],
+ "isUnique": true
+ },
+ "world_candidates_status_idx": {
+ "name": "world_candidates_status_idx",
+ "columns": [
+ "status"
+ ],
+ "isUnique": false
+ },
+ "world_candidates_score_idx": {
+ "name": "world_candidates_score_idx",
+ "columns": [
+ "emergence_score"
+ ],
+ "isUnique": false
+ }
+ },
+ "foreignKeys": {
+ "world_category_candidates_weight_profile_id_world_weight_profiles_id_fk": {
+ "name": "world_category_candidates_weight_profile_id_world_weight_profiles_id_fk",
+ "tableFrom": "world_category_candidates",
+ "tableTo": "world_weight_profiles",
+ "columnsFrom": [
+ "weight_profile_id"
+ ],
+ "columnsTo": [
+ "id"
+ ],
+ "onDelete": "no action",
+ "onUpdate": "no action"
+ }
+ },
+ "compositePrimaryKeys": {},
+ "uniqueConstraints": {},
+ "checkConstraints": {}
+ },
+ "world_growth_events": {
+ "name": "world_growth_events",
+ "columns": {
+ "id": {
+ "name": "id",
+ "type": "text",
+ "primaryKey": true,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "candidate_id": {
+ "name": "candidate_id",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "event_type": {
+ "name": "event_type",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "from_stage": {
+ "name": "from_stage",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": false,
+ "autoincrement": false
+ },
+ "to_stage": {
+ "name": "to_stage",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": false,
+ "autoincrement": false
+ },
+ "actor_type": {
+ "name": "actor_type",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": "'system'"
+ },
+ "weight_profile_id": {
+ "name": "weight_profile_id",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": false,
+ "autoincrement": false
+ },
+ "evidence_json": {
+ "name": "evidence_json",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": "'{}'"
+ },
+ "reason": {
+ "name": "reason",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": "''"
+ },
+ "created_at": {
+ "name": "created_at",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": "CURRENT_TIMESTAMP"
+ }
+ },
+ "indexes": {
+ "world_events_candidate_idx": {
+ "name": "world_events_candidate_idx",
+ "columns": [
+ "candidate_id"
+ ],
+ "isUnique": false
+ }
+ },
+ "foreignKeys": {
+ "world_growth_events_candidate_id_world_category_candidates_id_fk": {
+ "name": "world_growth_events_candidate_id_world_category_candidates_id_fk",
+ "tableFrom": "world_growth_events",
+ "tableTo": "world_category_candidates",
+ "columnsFrom": [
+ "candidate_id"
+ ],
+ "columnsTo": [
+ "id"
+ ],
+ "onDelete": "cascade",
+ "onUpdate": "no action"
+ },
+ "world_growth_events_weight_profile_id_world_weight_profiles_id_fk": {
+ "name": "world_growth_events_weight_profile_id_world_weight_profiles_id_fk",
+ "tableFrom": "world_growth_events",
+ "tableTo": "world_weight_profiles",
+ "columnsFrom": [
+ "weight_profile_id"
+ ],
+ "columnsTo": [
+ "id"
+ ],
+ "onDelete": "no action",
+ "onUpdate": "no action"
+ }
+ },
+ "compositePrimaryKeys": {},
+ "uniqueConstraints": {},
+ "checkConstraints": {}
+ },
+ "world_signal_assignments": {
+ "name": "world_signal_assignments",
+ "columns": {
+ "id": {
+ "name": "id",
+ "type": "text",
+ "primaryKey": true,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "vault_id": {
+ "name": "vault_id",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "debt_id": {
+ "name": "debt_id",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "candidate_id": {
+ "name": "candidate_id",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "confidence": {
+ "name": "confidence",
+ "type": "real",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "assignment_source": {
+ "name": "assignment_source",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": "'ai'"
+ },
+ "taxonomy_version": {
+ "name": "taxonomy_version",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": 1
+ },
+ "created_at": {
+ "name": "created_at",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": "CURRENT_TIMESTAMP"
+ },
+ "updated_at": {
+ "name": "updated_at",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": "CURRENT_TIMESTAMP"
+ }
+ },
+ "indexes": {
+ "world_signal_assignments_debt_id_unique": {
+ "name": "world_signal_assignments_debt_id_unique",
+ "columns": [
+ "debt_id"
+ ],
+ "isUnique": true
+ },
+ "world_signals_vault_idx": {
+ "name": "world_signals_vault_idx",
+ "columns": [
+ "vault_id"
+ ],
+ "isUnique": false
+ },
+ "world_signals_candidate_idx": {
+ "name": "world_signals_candidate_idx",
+ "columns": [
+ "candidate_id"
+ ],
+ "isUnique": false
+ }
+ },
+ "foreignKeys": {
+ "world_signal_assignments_vault_id_vaults_id_fk": {
+ "name": "world_signal_assignments_vault_id_vaults_id_fk",
+ "tableFrom": "world_signal_assignments",
+ "tableTo": "vaults",
+ "columnsFrom": [
+ "vault_id"
+ ],
+ "columnsTo": [
+ "id"
+ ],
+ "onDelete": "cascade",
+ "onUpdate": "no action"
+ },
+ "world_signal_assignments_debt_id_debts_id_fk": {
+ "name": "world_signal_assignments_debt_id_debts_id_fk",
+ "tableFrom": "world_signal_assignments",
+ "tableTo": "debts",
+ "columnsFrom": [
+ "debt_id"
+ ],
+ "columnsTo": [
+ "id"
+ ],
+ "onDelete": "cascade",
+ "onUpdate": "no action"
+ },
+ "world_signal_assignments_candidate_id_world_category_candidates_id_fk": {
+ "name": "world_signal_assignments_candidate_id_world_category_candidates_id_fk",
+ "tableFrom": "world_signal_assignments",
+ "tableTo": "world_category_candidates",
+ "columnsFrom": [
+ "candidate_id"
+ ],
+ "columnsTo": [
+ "id"
+ ],
+ "onDelete": "cascade",
+ "onUpdate": "no action"
+ }
+ },
+ "compositePrimaryKeys": {},
+ "uniqueConstraints": {},
+ "checkConstraints": {}
+ },
+ "world_weight_profiles": {
+ "name": "world_weight_profiles",
+ "columns": {
+ "id": {
+ "name": "id",
+ "type": "text",
+ "primaryKey": true,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "version": {
+ "name": "version",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "status": {
+ "name": "status",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": "'draft'"
+ },
+ "frequency_weight": {
+ "name": "frequency_weight",
+ "type": "real",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "growth_weight": {
+ "name": "growth_weight",
+ "type": "real",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "geography_weight": {
+ "name": "geography_weight",
+ "type": "real",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "recurrence_weight": {
+ "name": "recurrence_weight",
+ "type": "real",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "connection_weight": {
+ "name": "connection_weight",
+ "type": "real",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "quality_weight": {
+ "name": "quality_weight",
+ "type": "real",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "proposed_by": {
+ "name": "proposed_by",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": "'human'"
+ },
+ "model_ref": {
+ "name": "model_ref",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": false,
+ "autoincrement": false
+ },
+ "rationale": {
+ "name": "rationale",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": "''"
+ },
+ "created_at": {
+ "name": "created_at",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": "CURRENT_TIMESTAMP"
+ },
+ "activated_at": {
+ "name": "activated_at",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": false,
+ "autoincrement": false
+ }
+ },
+ "indexes": {
+ "world_weight_profiles_version_unique": {
+ "name": "world_weight_profiles_version_unique",
+ "columns": [
+ "version"
+ ],
+ "isUnique": true
+ }
+ },
+ "foreignKeys": {},
+ "compositePrimaryKeys": {},
+ "uniqueConstraints": {},
+ "checkConstraints": {}
+ }
+ },
+ "views": {},
+ "enums": {},
+ "_meta": {
+ "schemas": {},
+ "tables": {},
+ "columns": {}
+ },
+ "internal": {
+ "indexes": {}
+ }
+}
\ No newline at end of file
diff --git a/drizzle/meta/0015_snapshot.json b/drizzle/meta/0015_snapshot.json
new file mode 100644
index 0000000..7606f40
--- /dev/null
+++ b/drizzle/meta/0015_snapshot.json
@@ -0,0 +1,3018 @@
+{
+ "version": "6",
+ "dialect": "sqlite",
+ "id": "c01d935a-ae6c-4ddb-a9d2-5e3e7feae809",
+ "prevId": "370226fd-3b9b-44e3-81bb-e48ff1ef1358",
+ "tables": {
+ "account_auth_limits": {
+ "name": "account_auth_limits",
+ "columns": {
+ "limit_key": {
+ "name": "limit_key",
+ "type": "text",
+ "primaryKey": true,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "action": {
+ "name": "action",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "window_key": {
+ "name": "window_key",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "attempts": {
+ "name": "attempts",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": 0
+ },
+ "updated_at": {
+ "name": "updated_at",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": "CURRENT_TIMESTAMP"
+ }
+ },
+ "indexes": {
+ "account_auth_limits_window_idx": {
+ "name": "account_auth_limits_window_idx",
+ "columns": [
+ "window_key"
+ ],
+ "isUnique": false
+ }
+ },
+ "foreignKeys": {},
+ "compositePrimaryKeys": {},
+ "uniqueConstraints": {},
+ "checkConstraints": {}
+ },
+ "account_sessions": {
+ "name": "account_sessions",
+ "columns": {
+ "id": {
+ "name": "id",
+ "type": "text",
+ "primaryKey": true,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "account_id": {
+ "name": "account_id",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "token_hash": {
+ "name": "token_hash",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "expires_at": {
+ "name": "expires_at",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "created_at": {
+ "name": "created_at",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": "CURRENT_TIMESTAMP"
+ },
+ "last_seen_at": {
+ "name": "last_seen_at",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": "CURRENT_TIMESTAMP"
+ }
+ },
+ "indexes": {
+ "account_sessions_token_hash_unique": {
+ "name": "account_sessions_token_hash_unique",
+ "columns": [
+ "token_hash"
+ ],
+ "isUnique": true
+ },
+ "account_sessions_account_idx": {
+ "name": "account_sessions_account_idx",
+ "columns": [
+ "account_id"
+ ],
+ "isUnique": false
+ },
+ "account_sessions_expires_idx": {
+ "name": "account_sessions_expires_idx",
+ "columns": [
+ "expires_at"
+ ],
+ "isUnique": false
+ }
+ },
+ "foreignKeys": {
+ "account_sessions_account_id_accounts_id_fk": {
+ "name": "account_sessions_account_id_accounts_id_fk",
+ "tableFrom": "account_sessions",
+ "tableTo": "accounts",
+ "columnsFrom": [
+ "account_id"
+ ],
+ "columnsTo": [
+ "id"
+ ],
+ "onDelete": "cascade",
+ "onUpdate": "no action"
+ }
+ },
+ "compositePrimaryKeys": {},
+ "uniqueConstraints": {},
+ "checkConstraints": {}
+ },
+ "account_vaults": {
+ "name": "account_vaults",
+ "columns": {
+ "account_id": {
+ "name": "account_id",
+ "type": "text",
+ "primaryKey": true,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "vault_id": {
+ "name": "vault_id",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "linked_at": {
+ "name": "linked_at",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": "CURRENT_TIMESTAMP"
+ }
+ },
+ "indexes": {
+ "account_vaults_vault_id_unique": {
+ "name": "account_vaults_vault_id_unique",
+ "columns": [
+ "vault_id"
+ ],
+ "isUnique": true
+ },
+ "account_vaults_vault_idx": {
+ "name": "account_vaults_vault_idx",
+ "columns": [
+ "vault_id"
+ ],
+ "isUnique": false
+ }
+ },
+ "foreignKeys": {
+ "account_vaults_account_id_accounts_id_fk": {
+ "name": "account_vaults_account_id_accounts_id_fk",
+ "tableFrom": "account_vaults",
+ "tableTo": "accounts",
+ "columnsFrom": [
+ "account_id"
+ ],
+ "columnsTo": [
+ "id"
+ ],
+ "onDelete": "cascade",
+ "onUpdate": "no action"
+ },
+ "account_vaults_vault_id_vaults_id_fk": {
+ "name": "account_vaults_vault_id_vaults_id_fk",
+ "tableFrom": "account_vaults",
+ "tableTo": "vaults",
+ "columnsFrom": [
+ "vault_id"
+ ],
+ "columnsTo": [
+ "id"
+ ],
+ "onDelete": "cascade",
+ "onUpdate": "no action"
+ }
+ },
+ "compositePrimaryKeys": {},
+ "uniqueConstraints": {},
+ "checkConstraints": {}
+ },
+ "accounts": {
+ "name": "accounts",
+ "columns": {
+ "id": {
+ "name": "id",
+ "type": "text",
+ "primaryKey": true,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "user_code": {
+ "name": "user_code",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "username": {
+ "name": "username",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "username_normalized": {
+ "name": "username_normalized",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "password_hash": {
+ "name": "password_hash",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "password_salt": {
+ "name": "password_salt",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "password_iterations": {
+ "name": "password_iterations",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "status": {
+ "name": "status",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": "'active'"
+ },
+ "signup_source": {
+ "name": "signup_source",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": "'direct'"
+ },
+ "created_at": {
+ "name": "created_at",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": "CURRENT_TIMESTAMP"
+ },
+ "updated_at": {
+ "name": "updated_at",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": "CURRENT_TIMESTAMP"
+ },
+ "last_login_at": {
+ "name": "last_login_at",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": false,
+ "autoincrement": false
+ },
+ "last_seen_at": {
+ "name": "last_seen_at",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": false,
+ "autoincrement": false
+ }
+ },
+ "indexes": {
+ "accounts_user_code_unique": {
+ "name": "accounts_user_code_unique",
+ "columns": [
+ "user_code"
+ ],
+ "isUnique": true
+ },
+ "accounts_username_normalized_unique": {
+ "name": "accounts_username_normalized_unique",
+ "columns": [
+ "username_normalized"
+ ],
+ "isUnique": true
+ },
+ "accounts_created_idx": {
+ "name": "accounts_created_idx",
+ "columns": [
+ "created_at"
+ ],
+ "isUnique": false
+ }
+ },
+ "foreignKeys": {},
+ "compositePrimaryKeys": {},
+ "uniqueConstraints": {},
+ "checkConstraints": {}
+ },
+ "ai_daily_usage": {
+ "name": "ai_daily_usage",
+ "columns": {
+ "id": {
+ "name": "id",
+ "type": "text",
+ "primaryKey": true,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "vault_id": {
+ "name": "vault_id",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "usage_date": {
+ "name": "usage_date",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "request_count": {
+ "name": "request_count",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": 0
+ },
+ "input_tokens": {
+ "name": "input_tokens",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": 0
+ },
+ "output_tokens": {
+ "name": "output_tokens",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": 0
+ },
+ "updated_at": {
+ "name": "updated_at",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": "CURRENT_TIMESTAMP"
+ }
+ },
+ "indexes": {
+ "ai_daily_usage_vault_date_unique": {
+ "name": "ai_daily_usage_vault_date_unique",
+ "columns": [
+ "vault_id",
+ "usage_date"
+ ],
+ "isUnique": true
+ },
+ "ai_daily_usage_date_idx": {
+ "name": "ai_daily_usage_date_idx",
+ "columns": [
+ "usage_date"
+ ],
+ "isUnique": false
+ }
+ },
+ "foreignKeys": {
+ "ai_daily_usage_vault_id_vaults_id_fk": {
+ "name": "ai_daily_usage_vault_id_vaults_id_fk",
+ "tableFrom": "ai_daily_usage",
+ "tableTo": "vaults",
+ "columnsFrom": [
+ "vault_id"
+ ],
+ "columnsTo": [
+ "id"
+ ],
+ "onDelete": "cascade",
+ "onUpdate": "no action"
+ }
+ },
+ "compositePrimaryKeys": {},
+ "uniqueConstraints": {},
+ "checkConstraints": {}
+ },
+ "beta_enrollments": {
+ "name": "beta_enrollments",
+ "columns": {
+ "id": {
+ "name": "id",
+ "type": "text",
+ "primaryKey": true,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "vault_id": {
+ "name": "vault_id",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "invite_digest": {
+ "name": "invite_digest",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "consent_version": {
+ "name": "consent_version",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "created_at": {
+ "name": "created_at",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": "CURRENT_TIMESTAMP"
+ }
+ },
+ "indexes": {
+ "beta_enrollments_vault_id_unique": {
+ "name": "beta_enrollments_vault_id_unique",
+ "columns": [
+ "vault_id"
+ ],
+ "isUnique": true
+ },
+ "beta_enrollments_created_idx": {
+ "name": "beta_enrollments_created_idx",
+ "columns": [
+ "created_at"
+ ],
+ "isUnique": false
+ }
+ },
+ "foreignKeys": {
+ "beta_enrollments_vault_id_vaults_id_fk": {
+ "name": "beta_enrollments_vault_id_vaults_id_fk",
+ "tableFrom": "beta_enrollments",
+ "tableTo": "vaults",
+ "columnsFrom": [
+ "vault_id"
+ ],
+ "columnsTo": [
+ "id"
+ ],
+ "onDelete": "cascade",
+ "onUpdate": "no action"
+ }
+ },
+ "compositePrimaryKeys": {},
+ "uniqueConstraints": {},
+ "checkConstraints": {}
+ },
+ "beta_feedback": {
+ "name": "beta_feedback",
+ "columns": {
+ "id": {
+ "name": "id",
+ "type": "text",
+ "primaryKey": true,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "vault_id": {
+ "name": "vault_id",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "category": {
+ "name": "category",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "rating": {
+ "name": "rating",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "message": {
+ "name": "message",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "page_path": {
+ "name": "page_path",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": "'/'"
+ },
+ "status": {
+ "name": "status",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": "'open'"
+ },
+ "created_at": {
+ "name": "created_at",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": "CURRENT_TIMESTAMP"
+ },
+ "resolved_at": {
+ "name": "resolved_at",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": false,
+ "autoincrement": false
+ }
+ },
+ "indexes": {
+ "beta_feedback_vault_idx": {
+ "name": "beta_feedback_vault_idx",
+ "columns": [
+ "vault_id"
+ ],
+ "isUnique": false
+ },
+ "beta_feedback_status_idx": {
+ "name": "beta_feedback_status_idx",
+ "columns": [
+ "status"
+ ],
+ "isUnique": false
+ }
+ },
+ "foreignKeys": {
+ "beta_feedback_vault_id_vaults_id_fk": {
+ "name": "beta_feedback_vault_id_vaults_id_fk",
+ "tableFrom": "beta_feedback",
+ "tableTo": "vaults",
+ "columnsFrom": [
+ "vault_id"
+ ],
+ "columnsTo": [
+ "id"
+ ],
+ "onDelete": "cascade",
+ "onUpdate": "no action"
+ }
+ },
+ "compositePrimaryKeys": {},
+ "uniqueConstraints": {},
+ "checkConstraints": {}
+ },
+ "beta_invite_counters": {
+ "name": "beta_invite_counters",
+ "columns": {
+ "invite_digest": {
+ "name": "invite_digest",
+ "type": "text",
+ "primaryKey": true,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "uses": {
+ "name": "uses",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": 0
+ },
+ "max_uses": {
+ "name": "max_uses",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "updated_at": {
+ "name": "updated_at",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": "CURRENT_TIMESTAMP"
+ }
+ },
+ "indexes": {},
+ "foreignKeys": {},
+ "compositePrimaryKeys": {},
+ "uniqueConstraints": {},
+ "checkConstraints": {}
+ },
+ "beta_runtime_settings": {
+ "name": "beta_runtime_settings",
+ "columns": {
+ "id": {
+ "name": "id",
+ "type": "text",
+ "primaryKey": true,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "signups_enabled": {
+ "name": "signups_enabled",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "updated_by_digest": {
+ "name": "updated_by_digest",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": false,
+ "autoincrement": false
+ },
+ "updated_at": {
+ "name": "updated_at",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": "CURRENT_TIMESTAMP"
+ }
+ },
+ "indexes": {},
+ "foreignKeys": {},
+ "compositePrimaryKeys": {},
+ "uniqueConstraints": {},
+ "checkConstraints": {}
+ },
+ "community_moderation_actions": {
+ "name": "community_moderation_actions",
+ "columns": {
+ "id": {
+ "name": "id",
+ "type": "text",
+ "primaryKey": true,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "story_id": {
+ "name": "story_id",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "actor_digest": {
+ "name": "actor_digest",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "action": {
+ "name": "action",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "from_status": {
+ "name": "from_status",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "to_status": {
+ "name": "to_status",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "note": {
+ "name": "note",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": "''"
+ },
+ "created_at": {
+ "name": "created_at",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": "CURRENT_TIMESTAMP"
+ }
+ },
+ "indexes": {
+ "community_moderation_story_idx": {
+ "name": "community_moderation_story_idx",
+ "columns": [
+ "story_id"
+ ],
+ "isUnique": false
+ },
+ "community_moderation_created_idx": {
+ "name": "community_moderation_created_idx",
+ "columns": [
+ "created_at"
+ ],
+ "isUnique": false
+ }
+ },
+ "foreignKeys": {
+ "community_moderation_actions_story_id_public_stories_id_fk": {
+ "name": "community_moderation_actions_story_id_public_stories_id_fk",
+ "tableFrom": "community_moderation_actions",
+ "tableTo": "public_stories",
+ "columnsFrom": [
+ "story_id"
+ ],
+ "columnsTo": [
+ "id"
+ ],
+ "onDelete": "cascade",
+ "onUpdate": "no action"
+ }
+ },
+ "compositePrimaryKeys": {},
+ "uniqueConstraints": {},
+ "checkConstraints": {}
+ },
+ "community_rate_limits": {
+ "name": "community_rate_limits",
+ "columns": {
+ "id": {
+ "name": "id",
+ "type": "text",
+ "primaryKey": true,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "vault_id": {
+ "name": "vault_id",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "action": {
+ "name": "action",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "window_key": {
+ "name": "window_key",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "count": {
+ "name": "count",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": 0
+ },
+ "updated_at": {
+ "name": "updated_at",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": "CURRENT_TIMESTAMP"
+ }
+ },
+ "indexes": {
+ "community_rate_vault_action_window_unique": {
+ "name": "community_rate_vault_action_window_unique",
+ "columns": [
+ "vault_id",
+ "action",
+ "window_key"
+ ],
+ "isUnique": true
+ },
+ "community_rate_window_idx": {
+ "name": "community_rate_window_idx",
+ "columns": [
+ "window_key"
+ ],
+ "isUnique": false
+ }
+ },
+ "foreignKeys": {
+ "community_rate_limits_vault_id_vaults_id_fk": {
+ "name": "community_rate_limits_vault_id_vaults_id_fk",
+ "tableFrom": "community_rate_limits",
+ "tableTo": "vaults",
+ "columnsFrom": [
+ "vault_id"
+ ],
+ "columnsTo": [
+ "id"
+ ],
+ "onDelete": "cascade",
+ "onUpdate": "no action"
+ }
+ },
+ "compositePrimaryKeys": {},
+ "uniqueConstraints": {},
+ "checkConstraints": {}
+ },
+ "debts": {
+ "name": "debts",
+ "columns": {
+ "id": {
+ "name": "id",
+ "type": "text",
+ "primaryKey": true,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "vault_id": {
+ "name": "vault_id",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "kind": {
+ "name": "kind",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "custom_label": {
+ "name": "custom_label",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": false,
+ "autoincrement": false
+ },
+ "currency": {
+ "name": "currency",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "original": {
+ "name": "original",
+ "type": "real",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "balance": {
+ "name": "balance",
+ "type": "real",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "monthly": {
+ "name": "monthly",
+ "type": "real",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "apr": {
+ "name": "apr",
+ "type": "real",
+ "primaryKey": false,
+ "notNull": false,
+ "autoincrement": false
+ },
+ "minimum_payment": {
+ "name": "minimum_payment",
+ "type": "real",
+ "primaryKey": false,
+ "notNull": false,
+ "autoincrement": false
+ },
+ "payment_status": {
+ "name": "payment_status",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": "'unknown'"
+ },
+ "remaining_months": {
+ "name": "remaining_months",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": false,
+ "autoincrement": false
+ },
+ "due_day": {
+ "name": "due_day",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "method": {
+ "name": "method",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "sharing_mode": {
+ "name": "sharing_mode",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": "'private'"
+ },
+ "last_paid_at": {
+ "name": "last_paid_at",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": false,
+ "autoincrement": false
+ },
+ "payments": {
+ "name": "payments",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": 0
+ },
+ "created_at": {
+ "name": "created_at",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": "CURRENT_TIMESTAMP"
+ },
+ "updated_at": {
+ "name": "updated_at",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": "CURRENT_TIMESTAMP"
+ }
+ },
+ "indexes": {
+ "debts_vault_id_idx": {
+ "name": "debts_vault_id_idx",
+ "columns": [
+ "vault_id"
+ ],
+ "isUnique": false
+ }
+ },
+ "foreignKeys": {
+ "debts_vault_id_vaults_id_fk": {
+ "name": "debts_vault_id_vaults_id_fk",
+ "tableFrom": "debts",
+ "tableTo": "vaults",
+ "columnsFrom": [
+ "vault_id"
+ ],
+ "columnsTo": [
+ "id"
+ ],
+ "onDelete": "cascade",
+ "onUpdate": "no action"
+ }
+ },
+ "compositePrimaryKeys": {},
+ "uniqueConstraints": {},
+ "checkConstraints": {}
+ },
+ "lucky_income_claims": {
+ "name": "lucky_income_claims",
+ "columns": {
+ "id": {
+ "name": "id",
+ "type": "text",
+ "primaryKey": true,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "vault_id": {
+ "name": "vault_id",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "event_date": {
+ "name": "event_date",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "created_at": {
+ "name": "created_at",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": "CURRENT_TIMESTAMP"
+ }
+ },
+ "indexes": {
+ "lucky_income_vault_day_unique": {
+ "name": "lucky_income_vault_day_unique",
+ "columns": [
+ "vault_id",
+ "event_date"
+ ],
+ "isUnique": true
+ }
+ },
+ "foreignKeys": {
+ "lucky_income_claims_vault_id_vaults_id_fk": {
+ "name": "lucky_income_claims_vault_id_vaults_id_fk",
+ "tableFrom": "lucky_income_claims",
+ "tableTo": "vaults",
+ "columnsFrom": [
+ "vault_id"
+ ],
+ "columnsTo": [
+ "id"
+ ],
+ "onDelete": "cascade",
+ "onUpdate": "no action"
+ }
+ },
+ "compositePrimaryKeys": {},
+ "uniqueConstraints": {},
+ "checkConstraints": {}
+ },
+ "owner_admins": {
+ "name": "owner_admins",
+ "columns": {
+ "id": {
+ "name": "id",
+ "type": "text",
+ "primaryKey": true,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "email_digest": {
+ "name": "email_digest",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "role": {
+ "name": "role",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": "'owner'"
+ },
+ "activated_at": {
+ "name": "activated_at",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": "CURRENT_TIMESTAMP"
+ },
+ "last_seen_at": {
+ "name": "last_seen_at",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": "CURRENT_TIMESTAMP"
+ }
+ },
+ "indexes": {
+ "owner_admins_email_digest_unique": {
+ "name": "owner_admins_email_digest_unique",
+ "columns": [
+ "email_digest"
+ ],
+ "isUnique": true
+ }
+ },
+ "foreignKeys": {},
+ "compositePrimaryKeys": {},
+ "uniqueConstraints": {},
+ "checkConstraints": {}
+ },
+ "payment_records": {
+ "name": "payment_records",
+ "columns": {
+ "id": {
+ "name": "id",
+ "type": "text",
+ "primaryKey": true,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "vault_id": {
+ "name": "vault_id",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "debt_id": {
+ "name": "debt_id",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "scheduled_date": {
+ "name": "scheduled_date",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": false,
+ "autoincrement": false
+ },
+ "confirmed_at": {
+ "name": "confirmed_at",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "event_date": {
+ "name": "event_date",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": false,
+ "autoincrement": false
+ },
+ "cash_payment": {
+ "name": "cash_payment",
+ "type": "real",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "new_balance": {
+ "name": "new_balance",
+ "type": "real",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "source": {
+ "name": "source",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": "'self_report'"
+ },
+ "income_type": {
+ "name": "income_type",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": false,
+ "autoincrement": false
+ },
+ "created_at": {
+ "name": "created_at",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": "CURRENT_TIMESTAMP"
+ }
+ },
+ "indexes": {
+ "payments_vault_id_idx": {
+ "name": "payments_vault_id_idx",
+ "columns": [
+ "vault_id"
+ ],
+ "isUnique": false
+ },
+ "payments_debt_id_idx": {
+ "name": "payments_debt_id_idx",
+ "columns": [
+ "debt_id"
+ ],
+ "isUnique": false
+ }
+ },
+ "foreignKeys": {
+ "payment_records_vault_id_vaults_id_fk": {
+ "name": "payment_records_vault_id_vaults_id_fk",
+ "tableFrom": "payment_records",
+ "tableTo": "vaults",
+ "columnsFrom": [
+ "vault_id"
+ ],
+ "columnsTo": [
+ "id"
+ ],
+ "onDelete": "cascade",
+ "onUpdate": "no action"
+ },
+ "payment_records_debt_id_debts_id_fk": {
+ "name": "payment_records_debt_id_debts_id_fk",
+ "tableFrom": "payment_records",
+ "tableTo": "debts",
+ "columnsFrom": [
+ "debt_id"
+ ],
+ "columnsTo": [
+ "id"
+ ],
+ "onDelete": "cascade",
+ "onUpdate": "no action"
+ }
+ },
+ "compositePrimaryKeys": {},
+ "uniqueConstraints": {},
+ "checkConstraints": {}
+ },
+ "policy_acceptances": {
+ "name": "policy_acceptances",
+ "columns": {
+ "id": {
+ "name": "id",
+ "type": "text",
+ "primaryKey": true,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "vault_id": {
+ "name": "vault_id",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "policy_key": {
+ "name": "policy_key",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "policy_version": {
+ "name": "policy_version",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "accepted_at": {
+ "name": "accepted_at",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": "CURRENT_TIMESTAMP"
+ }
+ },
+ "indexes": {
+ "policy_acceptance_vault_key_version_unique": {
+ "name": "policy_acceptance_vault_key_version_unique",
+ "columns": [
+ "vault_id",
+ "policy_key",
+ "policy_version"
+ ],
+ "isUnique": true
+ },
+ "policy_acceptance_vault_idx": {
+ "name": "policy_acceptance_vault_idx",
+ "columns": [
+ "vault_id"
+ ],
+ "isUnique": false
+ }
+ },
+ "foreignKeys": {
+ "policy_acceptances_vault_id_vaults_id_fk": {
+ "name": "policy_acceptances_vault_id_vaults_id_fk",
+ "tableFrom": "policy_acceptances",
+ "tableTo": "vaults",
+ "columnsFrom": [
+ "vault_id"
+ ],
+ "columnsTo": [
+ "id"
+ ],
+ "onDelete": "cascade",
+ "onUpdate": "no action"
+ }
+ },
+ "compositePrimaryKeys": {},
+ "uniqueConstraints": {},
+ "checkConstraints": {}
+ },
+ "public_stories": {
+ "name": "public_stories",
+ "columns": {
+ "id": {
+ "name": "id",
+ "type": "text",
+ "primaryKey": true,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "vault_id": {
+ "name": "vault_id",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "debt_id": {
+ "name": "debt_id",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "anonymous_name": {
+ "name": "anonymous_name",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "country_code": {
+ "name": "country_code",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": "''"
+ },
+ "debt_kind": {
+ "name": "debt_kind",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "amount_band": {
+ "name": "amount_band",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "currency": {
+ "name": "currency",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "repayment_approach": {
+ "name": "repayment_approach",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": "'other'"
+ },
+ "story_text": {
+ "name": "story_text",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "status": {
+ "name": "status",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": "'pending'"
+ },
+ "created_at": {
+ "name": "created_at",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": "CURRENT_TIMESTAMP"
+ },
+ "updated_at": {
+ "name": "updated_at",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": "CURRENT_TIMESTAMP"
+ }
+ },
+ "indexes": {
+ "public_stories_status_idx": {
+ "name": "public_stories_status_idx",
+ "columns": [
+ "status"
+ ],
+ "isUnique": false
+ },
+ "public_stories_vault_idx": {
+ "name": "public_stories_vault_idx",
+ "columns": [
+ "vault_id"
+ ],
+ "isUnique": false
+ }
+ },
+ "foreignKeys": {
+ "public_stories_vault_id_vaults_id_fk": {
+ "name": "public_stories_vault_id_vaults_id_fk",
+ "tableFrom": "public_stories",
+ "tableTo": "vaults",
+ "columnsFrom": [
+ "vault_id"
+ ],
+ "columnsTo": [
+ "id"
+ ],
+ "onDelete": "cascade",
+ "onUpdate": "no action"
+ },
+ "public_stories_debt_id_debts_id_fk": {
+ "name": "public_stories_debt_id_debts_id_fk",
+ "tableFrom": "public_stories",
+ "tableTo": "debts",
+ "columnsFrom": [
+ "debt_id"
+ ],
+ "columnsTo": [
+ "id"
+ ],
+ "onDelete": "cascade",
+ "onUpdate": "no action"
+ }
+ },
+ "compositePrimaryKeys": {},
+ "uniqueConstraints": {},
+ "checkConstraints": {}
+ },
+ "referral_codes": {
+ "name": "referral_codes",
+ "columns": {
+ "id": {
+ "name": "id",
+ "type": "text",
+ "primaryKey": true,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "vault_id": {
+ "name": "vault_id",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "code": {
+ "name": "code",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "status": {
+ "name": "status",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": "'active'"
+ },
+ "created_at": {
+ "name": "created_at",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": "CURRENT_TIMESTAMP"
+ }
+ },
+ "indexes": {
+ "referral_codes_vault_id_unique": {
+ "name": "referral_codes_vault_id_unique",
+ "columns": [
+ "vault_id"
+ ],
+ "isUnique": true
+ },
+ "referral_codes_code_unique": {
+ "name": "referral_codes_code_unique",
+ "columns": [
+ "code"
+ ],
+ "isUnique": true
+ },
+ "referral_codes_status_idx": {
+ "name": "referral_codes_status_idx",
+ "columns": [
+ "status"
+ ],
+ "isUnique": false
+ }
+ },
+ "foreignKeys": {
+ "referral_codes_vault_id_vaults_id_fk": {
+ "name": "referral_codes_vault_id_vaults_id_fk",
+ "tableFrom": "referral_codes",
+ "tableTo": "vaults",
+ "columnsFrom": [
+ "vault_id"
+ ],
+ "columnsTo": [
+ "id"
+ ],
+ "onDelete": "cascade",
+ "onUpdate": "no action"
+ }
+ },
+ "compositePrimaryKeys": {},
+ "uniqueConstraints": {},
+ "checkConstraints": {}
+ },
+ "referral_relationships": {
+ "name": "referral_relationships",
+ "columns": {
+ "id": {
+ "name": "id",
+ "type": "text",
+ "primaryKey": true,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "inviter_vault_id": {
+ "name": "inviter_vault_id",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "invited_vault_id": {
+ "name": "invited_vault_id",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "code_id": {
+ "name": "code_id",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "status": {
+ "name": "status",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": "'pending'"
+ },
+ "qualified_at": {
+ "name": "qualified_at",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": false,
+ "autoincrement": false
+ },
+ "rewarded_at": {
+ "name": "rewarded_at",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": false,
+ "autoincrement": false
+ },
+ "created_at": {
+ "name": "created_at",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": "CURRENT_TIMESTAMP"
+ }
+ },
+ "indexes": {
+ "referral_relationships_invited_vault_id_unique": {
+ "name": "referral_relationships_invited_vault_id_unique",
+ "columns": [
+ "invited_vault_id"
+ ],
+ "isUnique": true
+ },
+ "referrals_inviter_status_idx": {
+ "name": "referrals_inviter_status_idx",
+ "columns": [
+ "inviter_vault_id",
+ "status"
+ ],
+ "isUnique": false
+ },
+ "referrals_created_idx": {
+ "name": "referrals_created_idx",
+ "columns": [
+ "created_at"
+ ],
+ "isUnique": false
+ }
+ },
+ "foreignKeys": {
+ "referral_relationships_inviter_vault_id_vaults_id_fk": {
+ "name": "referral_relationships_inviter_vault_id_vaults_id_fk",
+ "tableFrom": "referral_relationships",
+ "tableTo": "vaults",
+ "columnsFrom": [
+ "inviter_vault_id"
+ ],
+ "columnsTo": [
+ "id"
+ ],
+ "onDelete": "cascade",
+ "onUpdate": "no action"
+ },
+ "referral_relationships_invited_vault_id_vaults_id_fk": {
+ "name": "referral_relationships_invited_vault_id_vaults_id_fk",
+ "tableFrom": "referral_relationships",
+ "tableTo": "vaults",
+ "columnsFrom": [
+ "invited_vault_id"
+ ],
+ "columnsTo": [
+ "id"
+ ],
+ "onDelete": "cascade",
+ "onUpdate": "no action"
+ },
+ "referral_relationships_code_id_referral_codes_id_fk": {
+ "name": "referral_relationships_code_id_referral_codes_id_fk",
+ "tableFrom": "referral_relationships",
+ "tableTo": "referral_codes",
+ "columnsFrom": [
+ "code_id"
+ ],
+ "columnsTo": [
+ "id"
+ ],
+ "onDelete": "cascade",
+ "onUpdate": "no action"
+ }
+ },
+ "compositePrimaryKeys": {},
+ "uniqueConstraints": {},
+ "checkConstraints": {}
+ },
+ "shore_value_ledger": {
+ "name": "shore_value_ledger",
+ "columns": {
+ "id": {
+ "name": "id",
+ "type": "text",
+ "primaryKey": true,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "vault_id": {
+ "name": "vault_id",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "event_key": {
+ "name": "event_key",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "event_type": {
+ "name": "event_type",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "points": {
+ "name": "points",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "reference_id": {
+ "name": "reference_id",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": false,
+ "autoincrement": false
+ },
+ "created_at": {
+ "name": "created_at",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": "CURRENT_TIMESTAMP"
+ }
+ },
+ "indexes": {
+ "shore_value_ledger_event_key_unique": {
+ "name": "shore_value_ledger_event_key_unique",
+ "columns": [
+ "event_key"
+ ],
+ "isUnique": true
+ },
+ "shore_value_vault_created_idx": {
+ "name": "shore_value_vault_created_idx",
+ "columns": [
+ "vault_id",
+ "created_at"
+ ],
+ "isUnique": false
+ },
+ "shore_value_event_type_idx": {
+ "name": "shore_value_event_type_idx",
+ "columns": [
+ "event_type"
+ ],
+ "isUnique": false
+ }
+ },
+ "foreignKeys": {
+ "shore_value_ledger_vault_id_vaults_id_fk": {
+ "name": "shore_value_ledger_vault_id_vaults_id_fk",
+ "tableFrom": "shore_value_ledger",
+ "tableTo": "vaults",
+ "columnsFrom": [
+ "vault_id"
+ ],
+ "columnsTo": [
+ "id"
+ ],
+ "onDelete": "cascade",
+ "onUpdate": "no action"
+ }
+ },
+ "compositePrimaryKeys": {},
+ "uniqueConstraints": {},
+ "checkConstraints": {}
+ },
+ "starlight_gifts": {
+ "name": "starlight_gifts",
+ "columns": {
+ "id": {
+ "name": "id",
+ "type": "text",
+ "primaryKey": true,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "sender_vault_id": {
+ "name": "sender_vault_id",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "recipient_vault_id": {
+ "name": "recipient_vault_id",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "story_id": {
+ "name": "story_id",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": false,
+ "autoincrement": false
+ },
+ "points": {
+ "name": "points",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "gift_date": {
+ "name": "gift_date",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "idempotency_key": {
+ "name": "idempotency_key",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "created_at": {
+ "name": "created_at",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": "CURRENT_TIMESTAMP"
+ }
+ },
+ "indexes": {
+ "starlight_gifts_idempotency_key_unique": {
+ "name": "starlight_gifts_idempotency_key_unique",
+ "columns": [
+ "idempotency_key"
+ ],
+ "isUnique": true
+ },
+ "starlight_sender_created_idx": {
+ "name": "starlight_sender_created_idx",
+ "columns": [
+ "sender_vault_id",
+ "created_at"
+ ],
+ "isUnique": false
+ },
+ "starlight_recipient_created_idx": {
+ "name": "starlight_recipient_created_idx",
+ "columns": [
+ "recipient_vault_id",
+ "created_at"
+ ],
+ "isUnique": false
+ }
+ },
+ "foreignKeys": {
+ "starlight_gifts_sender_vault_id_vaults_id_fk": {
+ "name": "starlight_gifts_sender_vault_id_vaults_id_fk",
+ "tableFrom": "starlight_gifts",
+ "tableTo": "vaults",
+ "columnsFrom": [
+ "sender_vault_id"
+ ],
+ "columnsTo": [
+ "id"
+ ],
+ "onDelete": "cascade",
+ "onUpdate": "no action"
+ },
+ "starlight_gifts_recipient_vault_id_vaults_id_fk": {
+ "name": "starlight_gifts_recipient_vault_id_vaults_id_fk",
+ "tableFrom": "starlight_gifts",
+ "tableTo": "vaults",
+ "columnsFrom": [
+ "recipient_vault_id"
+ ],
+ "columnsTo": [
+ "id"
+ ],
+ "onDelete": "cascade",
+ "onUpdate": "no action"
+ }
+ },
+ "compositePrimaryKeys": {},
+ "uniqueConstraints": {},
+ "checkConstraints": {}
+ },
+ "starlight_wallets": {
+ "name": "starlight_wallets",
+ "columns": {
+ "vault_id": {
+ "name": "vault_id",
+ "type": "text",
+ "primaryKey": true,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "available": {
+ "name": "available",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": 0
+ },
+ "lifetime_earned": {
+ "name": "lifetime_earned",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": 0
+ },
+ "lifetime_sent": {
+ "name": "lifetime_sent",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": 0
+ },
+ "lifetime_received": {
+ "name": "lifetime_received",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": 0
+ },
+ "updated_at": {
+ "name": "updated_at",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": "CURRENT_TIMESTAMP"
+ }
+ },
+ "indexes": {},
+ "foreignKeys": {
+ "starlight_wallets_vault_id_vaults_id_fk": {
+ "name": "starlight_wallets_vault_id_vaults_id_fk",
+ "tableFrom": "starlight_wallets",
+ "tableTo": "vaults",
+ "columnsFrom": [
+ "vault_id"
+ ],
+ "columnsTo": [
+ "id"
+ ],
+ "onDelete": "cascade",
+ "onUpdate": "no action"
+ }
+ },
+ "compositePrimaryKeys": {},
+ "uniqueConstraints": {},
+ "checkConstraints": {}
+ },
+ "story_encouragements": {
+ "name": "story_encouragements",
+ "columns": {
+ "id": {
+ "name": "id",
+ "type": "text",
+ "primaryKey": true,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "story_id": {
+ "name": "story_id",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "vault_id": {
+ "name": "vault_id",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "created_at": {
+ "name": "created_at",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": "CURRENT_TIMESTAMP"
+ }
+ },
+ "indexes": {
+ "story_encouragement_unique": {
+ "name": "story_encouragement_unique",
+ "columns": [
+ "story_id",
+ "vault_id"
+ ],
+ "isUnique": true
+ },
+ "story_encouragement_story_idx": {
+ "name": "story_encouragement_story_idx",
+ "columns": [
+ "story_id"
+ ],
+ "isUnique": false
+ }
+ },
+ "foreignKeys": {
+ "story_encouragements_story_id_public_stories_id_fk": {
+ "name": "story_encouragements_story_id_public_stories_id_fk",
+ "tableFrom": "story_encouragements",
+ "tableTo": "public_stories",
+ "columnsFrom": [
+ "story_id"
+ ],
+ "columnsTo": [
+ "id"
+ ],
+ "onDelete": "cascade",
+ "onUpdate": "no action"
+ },
+ "story_encouragements_vault_id_vaults_id_fk": {
+ "name": "story_encouragements_vault_id_vaults_id_fk",
+ "tableFrom": "story_encouragements",
+ "tableTo": "vaults",
+ "columnsFrom": [
+ "vault_id"
+ ],
+ "columnsTo": [
+ "id"
+ ],
+ "onDelete": "cascade",
+ "onUpdate": "no action"
+ }
+ },
+ "compositePrimaryKeys": {},
+ "uniqueConstraints": {},
+ "checkConstraints": {}
+ },
+ "story_reports": {
+ "name": "story_reports",
+ "columns": {
+ "id": {
+ "name": "id",
+ "type": "text",
+ "primaryKey": true,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "story_id": {
+ "name": "story_id",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "reporter_vault_id": {
+ "name": "reporter_vault_id",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "reason": {
+ "name": "reason",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "details": {
+ "name": "details",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": "''"
+ },
+ "status": {
+ "name": "status",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": "'open'"
+ },
+ "created_at": {
+ "name": "created_at",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": "CURRENT_TIMESTAMP"
+ },
+ "resolved_at": {
+ "name": "resolved_at",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": false,
+ "autoincrement": false
+ }
+ },
+ "indexes": {
+ "story_report_unique": {
+ "name": "story_report_unique",
+ "columns": [
+ "story_id",
+ "reporter_vault_id"
+ ],
+ "isUnique": true
+ },
+ "story_reports_status_idx": {
+ "name": "story_reports_status_idx",
+ "columns": [
+ "status"
+ ],
+ "isUnique": false
+ }
+ },
+ "foreignKeys": {
+ "story_reports_story_id_public_stories_id_fk": {
+ "name": "story_reports_story_id_public_stories_id_fk",
+ "tableFrom": "story_reports",
+ "tableTo": "public_stories",
+ "columnsFrom": [
+ "story_id"
+ ],
+ "columnsTo": [
+ "id"
+ ],
+ "onDelete": "cascade",
+ "onUpdate": "no action"
+ },
+ "story_reports_reporter_vault_id_vaults_id_fk": {
+ "name": "story_reports_reporter_vault_id_vaults_id_fk",
+ "tableFrom": "story_reports",
+ "tableTo": "vaults",
+ "columnsFrom": [
+ "reporter_vault_id"
+ ],
+ "columnsTo": [
+ "id"
+ ],
+ "onDelete": "cascade",
+ "onUpdate": "no action"
+ }
+ },
+ "compositePrimaryKeys": {},
+ "uniqueConstraints": {},
+ "checkConstraints": {}
+ },
+ "vaults": {
+ "name": "vaults",
+ "columns": {
+ "id": {
+ "name": "id",
+ "type": "text",
+ "primaryKey": true,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "recovery_hash": {
+ "name": "recovery_hash",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "alias": {
+ "name": "alias",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "region": {
+ "name": "region",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "pressure": {
+ "name": "pressure",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": "''"
+ },
+ "age_band": {
+ "name": "age_band",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": "''"
+ },
+ "gender": {
+ "name": "gender",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": "''"
+ },
+ "mbti": {
+ "name": "mbti",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": "''"
+ },
+ "zodiac": {
+ "name": "zodiac",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": "''"
+ },
+ "self_description": {
+ "name": "self_description",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": "''"
+ },
+ "repayment_plan": {
+ "name": "repayment_plan",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": "''"
+ },
+ "repayment_outlook": {
+ "name": "repayment_outlook",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": "''"
+ },
+ "income_plan": {
+ "name": "income_plan",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": "''"
+ },
+ "position_x": {
+ "name": "position_x",
+ "type": "real",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": 47
+ },
+ "position_y": {
+ "name": "position_y",
+ "type": "real",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": 63
+ },
+ "locale": {
+ "name": "locale",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": "'zh'"
+ },
+ "country_code": {
+ "name": "country_code",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": "''"
+ },
+ "country_name": {
+ "name": "country_name",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": "''"
+ },
+ "display_currency": {
+ "name": "display_currency",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": "'CNY'"
+ },
+ "monthly_income": {
+ "name": "monthly_income",
+ "type": "real",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": 0
+ },
+ "monthly_expenses": {
+ "name": "monthly_expenses",
+ "type": "real",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": 0
+ },
+ "discovery_consent": {
+ "name": "discovery_consent",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": false
+ },
+ "created_at": {
+ "name": "created_at",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": "CURRENT_TIMESTAMP"
+ },
+ "updated_at": {
+ "name": "updated_at",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": "CURRENT_TIMESTAMP"
+ }
+ },
+ "indexes": {
+ "vaults_recovery_hash_unique": {
+ "name": "vaults_recovery_hash_unique",
+ "columns": [
+ "recovery_hash"
+ ],
+ "isUnique": true
+ }
+ },
+ "foreignKeys": {},
+ "compositePrimaryKeys": {},
+ "uniqueConstraints": {},
+ "checkConstraints": {}
+ },
+ "world_category_candidates": {
+ "name": "world_category_candidates",
+ "columns": {
+ "id": {
+ "name": "id",
+ "type": "text",
+ "primaryKey": true,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "canonical_key": {
+ "name": "canonical_key",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "parent_kind": {
+ "name": "parent_kind",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": "'other'"
+ },
+ "name_zh": {
+ "name": "name_zh",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "name_en": {
+ "name": "name_en",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "description_zh": {
+ "name": "description_zh",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": "''"
+ },
+ "description_en": {
+ "name": "description_en",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": "''"
+ },
+ "status": {
+ "name": "status",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": "'candidate'"
+ },
+ "stage": {
+ "name": "stage",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": 0
+ },
+ "confidence": {
+ "name": "confidence",
+ "type": "real",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": 0
+ },
+ "unique_vaults": {
+ "name": "unique_vaults",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": 0
+ },
+ "region_count": {
+ "name": "region_count",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": 0
+ },
+ "mention_count": {
+ "name": "mention_count",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": 0
+ },
+ "emergence_score": {
+ "name": "emergence_score",
+ "type": "real",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": 0
+ },
+ "weight_profile_id": {
+ "name": "weight_profile_id",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": false,
+ "autoincrement": false
+ },
+ "merged_into_id": {
+ "name": "merged_into_id",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": false,
+ "autoincrement": false
+ },
+ "proposed_at": {
+ "name": "proposed_at",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": "CURRENT_TIMESTAMP"
+ },
+ "reviewed_at": {
+ "name": "reviewed_at",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": false,
+ "autoincrement": false
+ },
+ "published_at": {
+ "name": "published_at",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": false,
+ "autoincrement": false
+ },
+ "updated_at": {
+ "name": "updated_at",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": "CURRENT_TIMESTAMP"
+ }
+ },
+ "indexes": {
+ "world_category_candidates_canonical_key_unique": {
+ "name": "world_category_candidates_canonical_key_unique",
+ "columns": [
+ "canonical_key"
+ ],
+ "isUnique": true
+ },
+ "world_candidates_status_idx": {
+ "name": "world_candidates_status_idx",
+ "columns": [
+ "status"
+ ],
+ "isUnique": false
+ },
+ "world_candidates_score_idx": {
+ "name": "world_candidates_score_idx",
+ "columns": [
+ "emergence_score"
+ ],
+ "isUnique": false
+ }
+ },
+ "foreignKeys": {
+ "world_category_candidates_weight_profile_id_world_weight_profiles_id_fk": {
+ "name": "world_category_candidates_weight_profile_id_world_weight_profiles_id_fk",
+ "tableFrom": "world_category_candidates",
+ "tableTo": "world_weight_profiles",
+ "columnsFrom": [
+ "weight_profile_id"
+ ],
+ "columnsTo": [
+ "id"
+ ],
+ "onDelete": "no action",
+ "onUpdate": "no action"
+ }
+ },
+ "compositePrimaryKeys": {},
+ "uniqueConstraints": {},
+ "checkConstraints": {}
+ },
+ "world_growth_events": {
+ "name": "world_growth_events",
+ "columns": {
+ "id": {
+ "name": "id",
+ "type": "text",
+ "primaryKey": true,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "candidate_id": {
+ "name": "candidate_id",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "event_type": {
+ "name": "event_type",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "from_stage": {
+ "name": "from_stage",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": false,
+ "autoincrement": false
+ },
+ "to_stage": {
+ "name": "to_stage",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": false,
+ "autoincrement": false
+ },
+ "actor_type": {
+ "name": "actor_type",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": "'system'"
+ },
+ "weight_profile_id": {
+ "name": "weight_profile_id",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": false,
+ "autoincrement": false
+ },
+ "evidence_json": {
+ "name": "evidence_json",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": "'{}'"
+ },
+ "reason": {
+ "name": "reason",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": "''"
+ },
+ "created_at": {
+ "name": "created_at",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": "CURRENT_TIMESTAMP"
+ }
+ },
+ "indexes": {
+ "world_events_candidate_idx": {
+ "name": "world_events_candidate_idx",
+ "columns": [
+ "candidate_id"
+ ],
+ "isUnique": false
+ }
+ },
+ "foreignKeys": {
+ "world_growth_events_candidate_id_world_category_candidates_id_fk": {
+ "name": "world_growth_events_candidate_id_world_category_candidates_id_fk",
+ "tableFrom": "world_growth_events",
+ "tableTo": "world_category_candidates",
+ "columnsFrom": [
+ "candidate_id"
+ ],
+ "columnsTo": [
+ "id"
+ ],
+ "onDelete": "cascade",
+ "onUpdate": "no action"
+ },
+ "world_growth_events_weight_profile_id_world_weight_profiles_id_fk": {
+ "name": "world_growth_events_weight_profile_id_world_weight_profiles_id_fk",
+ "tableFrom": "world_growth_events",
+ "tableTo": "world_weight_profiles",
+ "columnsFrom": [
+ "weight_profile_id"
+ ],
+ "columnsTo": [
+ "id"
+ ],
+ "onDelete": "no action",
+ "onUpdate": "no action"
+ }
+ },
+ "compositePrimaryKeys": {},
+ "uniqueConstraints": {},
+ "checkConstraints": {}
+ },
+ "world_signal_assignments": {
+ "name": "world_signal_assignments",
+ "columns": {
+ "id": {
+ "name": "id",
+ "type": "text",
+ "primaryKey": true,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "vault_id": {
+ "name": "vault_id",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "debt_id": {
+ "name": "debt_id",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "candidate_id": {
+ "name": "candidate_id",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "confidence": {
+ "name": "confidence",
+ "type": "real",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "assignment_source": {
+ "name": "assignment_source",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": "'ai'"
+ },
+ "taxonomy_version": {
+ "name": "taxonomy_version",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": 1
+ },
+ "created_at": {
+ "name": "created_at",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": "CURRENT_TIMESTAMP"
+ },
+ "updated_at": {
+ "name": "updated_at",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": "CURRENT_TIMESTAMP"
+ }
+ },
+ "indexes": {
+ "world_signal_assignments_debt_id_unique": {
+ "name": "world_signal_assignments_debt_id_unique",
+ "columns": [
+ "debt_id"
+ ],
+ "isUnique": true
+ },
+ "world_signals_vault_idx": {
+ "name": "world_signals_vault_idx",
+ "columns": [
+ "vault_id"
+ ],
+ "isUnique": false
+ },
+ "world_signals_candidate_idx": {
+ "name": "world_signals_candidate_idx",
+ "columns": [
+ "candidate_id"
+ ],
+ "isUnique": false
+ }
+ },
+ "foreignKeys": {
+ "world_signal_assignments_vault_id_vaults_id_fk": {
+ "name": "world_signal_assignments_vault_id_vaults_id_fk",
+ "tableFrom": "world_signal_assignments",
+ "tableTo": "vaults",
+ "columnsFrom": [
+ "vault_id"
+ ],
+ "columnsTo": [
+ "id"
+ ],
+ "onDelete": "cascade",
+ "onUpdate": "no action"
+ },
+ "world_signal_assignments_debt_id_debts_id_fk": {
+ "name": "world_signal_assignments_debt_id_debts_id_fk",
+ "tableFrom": "world_signal_assignments",
+ "tableTo": "debts",
+ "columnsFrom": [
+ "debt_id"
+ ],
+ "columnsTo": [
+ "id"
+ ],
+ "onDelete": "cascade",
+ "onUpdate": "no action"
+ },
+ "world_signal_assignments_candidate_id_world_category_candidates_id_fk": {
+ "name": "world_signal_assignments_candidate_id_world_category_candidates_id_fk",
+ "tableFrom": "world_signal_assignments",
+ "tableTo": "world_category_candidates",
+ "columnsFrom": [
+ "candidate_id"
+ ],
+ "columnsTo": [
+ "id"
+ ],
+ "onDelete": "cascade",
+ "onUpdate": "no action"
+ }
+ },
+ "compositePrimaryKeys": {},
+ "uniqueConstraints": {},
+ "checkConstraints": {}
+ },
+ "world_weight_profiles": {
+ "name": "world_weight_profiles",
+ "columns": {
+ "id": {
+ "name": "id",
+ "type": "text",
+ "primaryKey": true,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "version": {
+ "name": "version",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "status": {
+ "name": "status",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": "'draft'"
+ },
+ "frequency_weight": {
+ "name": "frequency_weight",
+ "type": "real",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "growth_weight": {
+ "name": "growth_weight",
+ "type": "real",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "geography_weight": {
+ "name": "geography_weight",
+ "type": "real",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "recurrence_weight": {
+ "name": "recurrence_weight",
+ "type": "real",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "connection_weight": {
+ "name": "connection_weight",
+ "type": "real",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "quality_weight": {
+ "name": "quality_weight",
+ "type": "real",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "proposed_by": {
+ "name": "proposed_by",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": "'human'"
+ },
+ "model_ref": {
+ "name": "model_ref",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": false,
+ "autoincrement": false
+ },
+ "rationale": {
+ "name": "rationale",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": "''"
+ },
+ "created_at": {
+ "name": "created_at",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": "CURRENT_TIMESTAMP"
+ },
+ "activated_at": {
+ "name": "activated_at",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": false,
+ "autoincrement": false
+ }
+ },
+ "indexes": {
+ "world_weight_profiles_version_unique": {
+ "name": "world_weight_profiles_version_unique",
+ "columns": [
+ "version"
+ ],
+ "isUnique": true
+ }
+ },
+ "foreignKeys": {},
+ "compositePrimaryKeys": {},
+ "uniqueConstraints": {},
+ "checkConstraints": {}
+ }
+ },
+ "views": {},
+ "enums": {},
+ "_meta": {
+ "schemas": {},
+ "tables": {},
+ "columns": {}
+ },
+ "internal": {
+ "indexes": {}
+ }
+}
\ No newline at end of file
diff --git a/drizzle/meta/0016_snapshot.json b/drizzle/meta/0016_snapshot.json
new file mode 100644
index 0000000..7fedf32
--- /dev/null
+++ b/drizzle/meta/0016_snapshot.json
@@ -0,0 +1,3046 @@
+{
+ "version": "6",
+ "dialect": "sqlite",
+ "id": "5edb23cb-cd2c-44d2-82b0-d875d54a29bc",
+ "prevId": "c01d935a-ae6c-4ddb-a9d2-5e3e7feae809",
+ "tables": {
+ "account_auth_limits": {
+ "name": "account_auth_limits",
+ "columns": {
+ "limit_key": {
+ "name": "limit_key",
+ "type": "text",
+ "primaryKey": true,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "action": {
+ "name": "action",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "window_key": {
+ "name": "window_key",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "attempts": {
+ "name": "attempts",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": 0
+ },
+ "updated_at": {
+ "name": "updated_at",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": "CURRENT_TIMESTAMP"
+ }
+ },
+ "indexes": {
+ "account_auth_limits_window_idx": {
+ "name": "account_auth_limits_window_idx",
+ "columns": [
+ "window_key"
+ ],
+ "isUnique": false
+ }
+ },
+ "foreignKeys": {},
+ "compositePrimaryKeys": {},
+ "uniqueConstraints": {},
+ "checkConstraints": {}
+ },
+ "account_sessions": {
+ "name": "account_sessions",
+ "columns": {
+ "id": {
+ "name": "id",
+ "type": "text",
+ "primaryKey": true,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "account_id": {
+ "name": "account_id",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "token_hash": {
+ "name": "token_hash",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "expires_at": {
+ "name": "expires_at",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "created_at": {
+ "name": "created_at",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": "CURRENT_TIMESTAMP"
+ },
+ "last_seen_at": {
+ "name": "last_seen_at",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": "CURRENT_TIMESTAMP"
+ }
+ },
+ "indexes": {
+ "account_sessions_token_hash_unique": {
+ "name": "account_sessions_token_hash_unique",
+ "columns": [
+ "token_hash"
+ ],
+ "isUnique": true
+ },
+ "account_sessions_account_idx": {
+ "name": "account_sessions_account_idx",
+ "columns": [
+ "account_id"
+ ],
+ "isUnique": false
+ },
+ "account_sessions_expires_idx": {
+ "name": "account_sessions_expires_idx",
+ "columns": [
+ "expires_at"
+ ],
+ "isUnique": false
+ }
+ },
+ "foreignKeys": {
+ "account_sessions_account_id_accounts_id_fk": {
+ "name": "account_sessions_account_id_accounts_id_fk",
+ "tableFrom": "account_sessions",
+ "tableTo": "accounts",
+ "columnsFrom": [
+ "account_id"
+ ],
+ "columnsTo": [
+ "id"
+ ],
+ "onDelete": "cascade",
+ "onUpdate": "no action"
+ }
+ },
+ "compositePrimaryKeys": {},
+ "uniqueConstraints": {},
+ "checkConstraints": {}
+ },
+ "account_vaults": {
+ "name": "account_vaults",
+ "columns": {
+ "account_id": {
+ "name": "account_id",
+ "type": "text",
+ "primaryKey": true,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "vault_id": {
+ "name": "vault_id",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "linked_at": {
+ "name": "linked_at",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": "CURRENT_TIMESTAMP"
+ }
+ },
+ "indexes": {
+ "account_vaults_vault_id_unique": {
+ "name": "account_vaults_vault_id_unique",
+ "columns": [
+ "vault_id"
+ ],
+ "isUnique": true
+ },
+ "account_vaults_vault_idx": {
+ "name": "account_vaults_vault_idx",
+ "columns": [
+ "vault_id"
+ ],
+ "isUnique": false
+ }
+ },
+ "foreignKeys": {
+ "account_vaults_account_id_accounts_id_fk": {
+ "name": "account_vaults_account_id_accounts_id_fk",
+ "tableFrom": "account_vaults",
+ "tableTo": "accounts",
+ "columnsFrom": [
+ "account_id"
+ ],
+ "columnsTo": [
+ "id"
+ ],
+ "onDelete": "cascade",
+ "onUpdate": "no action"
+ },
+ "account_vaults_vault_id_vaults_id_fk": {
+ "name": "account_vaults_vault_id_vaults_id_fk",
+ "tableFrom": "account_vaults",
+ "tableTo": "vaults",
+ "columnsFrom": [
+ "vault_id"
+ ],
+ "columnsTo": [
+ "id"
+ ],
+ "onDelete": "cascade",
+ "onUpdate": "no action"
+ }
+ },
+ "compositePrimaryKeys": {},
+ "uniqueConstraints": {},
+ "checkConstraints": {}
+ },
+ "accounts": {
+ "name": "accounts",
+ "columns": {
+ "id": {
+ "name": "id",
+ "type": "text",
+ "primaryKey": true,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "user_code": {
+ "name": "user_code",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "username": {
+ "name": "username",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "username_normalized": {
+ "name": "username_normalized",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "password_hash": {
+ "name": "password_hash",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "password_salt": {
+ "name": "password_salt",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "password_iterations": {
+ "name": "password_iterations",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "status": {
+ "name": "status",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": "'active'"
+ },
+ "signup_source": {
+ "name": "signup_source",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": "'direct'"
+ },
+ "created_at": {
+ "name": "created_at",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": "CURRENT_TIMESTAMP"
+ },
+ "updated_at": {
+ "name": "updated_at",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": "CURRENT_TIMESTAMP"
+ },
+ "last_login_at": {
+ "name": "last_login_at",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": false,
+ "autoincrement": false
+ },
+ "last_seen_at": {
+ "name": "last_seen_at",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": false,
+ "autoincrement": false
+ }
+ },
+ "indexes": {
+ "accounts_user_code_unique": {
+ "name": "accounts_user_code_unique",
+ "columns": [
+ "user_code"
+ ],
+ "isUnique": true
+ },
+ "accounts_username_normalized_unique": {
+ "name": "accounts_username_normalized_unique",
+ "columns": [
+ "username_normalized"
+ ],
+ "isUnique": true
+ },
+ "accounts_created_idx": {
+ "name": "accounts_created_idx",
+ "columns": [
+ "created_at"
+ ],
+ "isUnique": false
+ }
+ },
+ "foreignKeys": {},
+ "compositePrimaryKeys": {},
+ "uniqueConstraints": {},
+ "checkConstraints": {}
+ },
+ "ai_daily_usage": {
+ "name": "ai_daily_usage",
+ "columns": {
+ "id": {
+ "name": "id",
+ "type": "text",
+ "primaryKey": true,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "vault_id": {
+ "name": "vault_id",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "usage_date": {
+ "name": "usage_date",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "request_count": {
+ "name": "request_count",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": 0
+ },
+ "input_tokens": {
+ "name": "input_tokens",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": 0
+ },
+ "output_tokens": {
+ "name": "output_tokens",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": 0
+ },
+ "updated_at": {
+ "name": "updated_at",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": "CURRENT_TIMESTAMP"
+ }
+ },
+ "indexes": {
+ "ai_daily_usage_vault_date_unique": {
+ "name": "ai_daily_usage_vault_date_unique",
+ "columns": [
+ "vault_id",
+ "usage_date"
+ ],
+ "isUnique": true
+ },
+ "ai_daily_usage_date_idx": {
+ "name": "ai_daily_usage_date_idx",
+ "columns": [
+ "usage_date"
+ ],
+ "isUnique": false
+ }
+ },
+ "foreignKeys": {
+ "ai_daily_usage_vault_id_vaults_id_fk": {
+ "name": "ai_daily_usage_vault_id_vaults_id_fk",
+ "tableFrom": "ai_daily_usage",
+ "tableTo": "vaults",
+ "columnsFrom": [
+ "vault_id"
+ ],
+ "columnsTo": [
+ "id"
+ ],
+ "onDelete": "cascade",
+ "onUpdate": "no action"
+ }
+ },
+ "compositePrimaryKeys": {},
+ "uniqueConstraints": {},
+ "checkConstraints": {}
+ },
+ "beta_enrollments": {
+ "name": "beta_enrollments",
+ "columns": {
+ "id": {
+ "name": "id",
+ "type": "text",
+ "primaryKey": true,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "vault_id": {
+ "name": "vault_id",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "invite_digest": {
+ "name": "invite_digest",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "consent_version": {
+ "name": "consent_version",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "created_at": {
+ "name": "created_at",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": "CURRENT_TIMESTAMP"
+ }
+ },
+ "indexes": {
+ "beta_enrollments_vault_id_unique": {
+ "name": "beta_enrollments_vault_id_unique",
+ "columns": [
+ "vault_id"
+ ],
+ "isUnique": true
+ },
+ "beta_enrollments_created_idx": {
+ "name": "beta_enrollments_created_idx",
+ "columns": [
+ "created_at"
+ ],
+ "isUnique": false
+ }
+ },
+ "foreignKeys": {
+ "beta_enrollments_vault_id_vaults_id_fk": {
+ "name": "beta_enrollments_vault_id_vaults_id_fk",
+ "tableFrom": "beta_enrollments",
+ "tableTo": "vaults",
+ "columnsFrom": [
+ "vault_id"
+ ],
+ "columnsTo": [
+ "id"
+ ],
+ "onDelete": "cascade",
+ "onUpdate": "no action"
+ }
+ },
+ "compositePrimaryKeys": {},
+ "uniqueConstraints": {},
+ "checkConstraints": {}
+ },
+ "beta_feedback": {
+ "name": "beta_feedback",
+ "columns": {
+ "id": {
+ "name": "id",
+ "type": "text",
+ "primaryKey": true,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "vault_id": {
+ "name": "vault_id",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "category": {
+ "name": "category",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "rating": {
+ "name": "rating",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "message": {
+ "name": "message",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "page_path": {
+ "name": "page_path",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": "'/'"
+ },
+ "status": {
+ "name": "status",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": "'open'"
+ },
+ "created_at": {
+ "name": "created_at",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": "CURRENT_TIMESTAMP"
+ },
+ "resolved_at": {
+ "name": "resolved_at",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": false,
+ "autoincrement": false
+ }
+ },
+ "indexes": {
+ "beta_feedback_vault_idx": {
+ "name": "beta_feedback_vault_idx",
+ "columns": [
+ "vault_id"
+ ],
+ "isUnique": false
+ },
+ "beta_feedback_status_idx": {
+ "name": "beta_feedback_status_idx",
+ "columns": [
+ "status"
+ ],
+ "isUnique": false
+ }
+ },
+ "foreignKeys": {
+ "beta_feedback_vault_id_vaults_id_fk": {
+ "name": "beta_feedback_vault_id_vaults_id_fk",
+ "tableFrom": "beta_feedback",
+ "tableTo": "vaults",
+ "columnsFrom": [
+ "vault_id"
+ ],
+ "columnsTo": [
+ "id"
+ ],
+ "onDelete": "cascade",
+ "onUpdate": "no action"
+ }
+ },
+ "compositePrimaryKeys": {},
+ "uniqueConstraints": {},
+ "checkConstraints": {}
+ },
+ "beta_invite_counters": {
+ "name": "beta_invite_counters",
+ "columns": {
+ "invite_digest": {
+ "name": "invite_digest",
+ "type": "text",
+ "primaryKey": true,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "uses": {
+ "name": "uses",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": 0
+ },
+ "max_uses": {
+ "name": "max_uses",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "updated_at": {
+ "name": "updated_at",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": "CURRENT_TIMESTAMP"
+ }
+ },
+ "indexes": {},
+ "foreignKeys": {},
+ "compositePrimaryKeys": {},
+ "uniqueConstraints": {},
+ "checkConstraints": {}
+ },
+ "beta_runtime_settings": {
+ "name": "beta_runtime_settings",
+ "columns": {
+ "id": {
+ "name": "id",
+ "type": "text",
+ "primaryKey": true,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "signups_enabled": {
+ "name": "signups_enabled",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "updated_by_digest": {
+ "name": "updated_by_digest",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": false,
+ "autoincrement": false
+ },
+ "updated_at": {
+ "name": "updated_at",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": "CURRENT_TIMESTAMP"
+ }
+ },
+ "indexes": {},
+ "foreignKeys": {},
+ "compositePrimaryKeys": {},
+ "uniqueConstraints": {},
+ "checkConstraints": {}
+ },
+ "community_moderation_actions": {
+ "name": "community_moderation_actions",
+ "columns": {
+ "id": {
+ "name": "id",
+ "type": "text",
+ "primaryKey": true,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "story_id": {
+ "name": "story_id",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "actor_digest": {
+ "name": "actor_digest",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "action": {
+ "name": "action",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "from_status": {
+ "name": "from_status",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "to_status": {
+ "name": "to_status",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "note": {
+ "name": "note",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": "''"
+ },
+ "created_at": {
+ "name": "created_at",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": "CURRENT_TIMESTAMP"
+ }
+ },
+ "indexes": {
+ "community_moderation_story_idx": {
+ "name": "community_moderation_story_idx",
+ "columns": [
+ "story_id"
+ ],
+ "isUnique": false
+ },
+ "community_moderation_created_idx": {
+ "name": "community_moderation_created_idx",
+ "columns": [
+ "created_at"
+ ],
+ "isUnique": false
+ }
+ },
+ "foreignKeys": {
+ "community_moderation_actions_story_id_public_stories_id_fk": {
+ "name": "community_moderation_actions_story_id_public_stories_id_fk",
+ "tableFrom": "community_moderation_actions",
+ "tableTo": "public_stories",
+ "columnsFrom": [
+ "story_id"
+ ],
+ "columnsTo": [
+ "id"
+ ],
+ "onDelete": "cascade",
+ "onUpdate": "no action"
+ }
+ },
+ "compositePrimaryKeys": {},
+ "uniqueConstraints": {},
+ "checkConstraints": {}
+ },
+ "community_rate_limits": {
+ "name": "community_rate_limits",
+ "columns": {
+ "id": {
+ "name": "id",
+ "type": "text",
+ "primaryKey": true,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "vault_id": {
+ "name": "vault_id",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "action": {
+ "name": "action",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "window_key": {
+ "name": "window_key",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "count": {
+ "name": "count",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": 0
+ },
+ "updated_at": {
+ "name": "updated_at",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": "CURRENT_TIMESTAMP"
+ }
+ },
+ "indexes": {
+ "community_rate_vault_action_window_unique": {
+ "name": "community_rate_vault_action_window_unique",
+ "columns": [
+ "vault_id",
+ "action",
+ "window_key"
+ ],
+ "isUnique": true
+ },
+ "community_rate_window_idx": {
+ "name": "community_rate_window_idx",
+ "columns": [
+ "window_key"
+ ],
+ "isUnique": false
+ }
+ },
+ "foreignKeys": {
+ "community_rate_limits_vault_id_vaults_id_fk": {
+ "name": "community_rate_limits_vault_id_vaults_id_fk",
+ "tableFrom": "community_rate_limits",
+ "tableTo": "vaults",
+ "columnsFrom": [
+ "vault_id"
+ ],
+ "columnsTo": [
+ "id"
+ ],
+ "onDelete": "cascade",
+ "onUpdate": "no action"
+ }
+ },
+ "compositePrimaryKeys": {},
+ "uniqueConstraints": {},
+ "checkConstraints": {}
+ },
+ "debts": {
+ "name": "debts",
+ "columns": {
+ "id": {
+ "name": "id",
+ "type": "text",
+ "primaryKey": true,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "vault_id": {
+ "name": "vault_id",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "kind": {
+ "name": "kind",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "custom_label": {
+ "name": "custom_label",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": false,
+ "autoincrement": false
+ },
+ "currency": {
+ "name": "currency",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "original": {
+ "name": "original",
+ "type": "real",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "balance": {
+ "name": "balance",
+ "type": "real",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "monthly": {
+ "name": "monthly",
+ "type": "real",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "apr": {
+ "name": "apr",
+ "type": "real",
+ "primaryKey": false,
+ "notNull": false,
+ "autoincrement": false
+ },
+ "minimum_payment": {
+ "name": "minimum_payment",
+ "type": "real",
+ "primaryKey": false,
+ "notNull": false,
+ "autoincrement": false
+ },
+ "payment_status": {
+ "name": "payment_status",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": "'unknown'"
+ },
+ "remaining_months": {
+ "name": "remaining_months",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": false,
+ "autoincrement": false
+ },
+ "due_day": {
+ "name": "due_day",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "method": {
+ "name": "method",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "sharing_mode": {
+ "name": "sharing_mode",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": "'private'"
+ },
+ "last_paid_at": {
+ "name": "last_paid_at",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": false,
+ "autoincrement": false
+ },
+ "payments": {
+ "name": "payments",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": 0
+ },
+ "created_at": {
+ "name": "created_at",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": "CURRENT_TIMESTAMP"
+ },
+ "updated_at": {
+ "name": "updated_at",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": "CURRENT_TIMESTAMP"
+ }
+ },
+ "indexes": {
+ "debts_vault_id_idx": {
+ "name": "debts_vault_id_idx",
+ "columns": [
+ "vault_id"
+ ],
+ "isUnique": false
+ }
+ },
+ "foreignKeys": {
+ "debts_vault_id_vaults_id_fk": {
+ "name": "debts_vault_id_vaults_id_fk",
+ "tableFrom": "debts",
+ "tableTo": "vaults",
+ "columnsFrom": [
+ "vault_id"
+ ],
+ "columnsTo": [
+ "id"
+ ],
+ "onDelete": "cascade",
+ "onUpdate": "no action"
+ }
+ },
+ "compositePrimaryKeys": {},
+ "uniqueConstraints": {},
+ "checkConstraints": {}
+ },
+ "lucky_income_claims": {
+ "name": "lucky_income_claims",
+ "columns": {
+ "id": {
+ "name": "id",
+ "type": "text",
+ "primaryKey": true,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "vault_id": {
+ "name": "vault_id",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "event_date": {
+ "name": "event_date",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "created_at": {
+ "name": "created_at",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": "CURRENT_TIMESTAMP"
+ }
+ },
+ "indexes": {
+ "lucky_income_vault_day_unique": {
+ "name": "lucky_income_vault_day_unique",
+ "columns": [
+ "vault_id",
+ "event_date"
+ ],
+ "isUnique": true
+ }
+ },
+ "foreignKeys": {
+ "lucky_income_claims_vault_id_vaults_id_fk": {
+ "name": "lucky_income_claims_vault_id_vaults_id_fk",
+ "tableFrom": "lucky_income_claims",
+ "tableTo": "vaults",
+ "columnsFrom": [
+ "vault_id"
+ ],
+ "columnsTo": [
+ "id"
+ ],
+ "onDelete": "cascade",
+ "onUpdate": "no action"
+ }
+ },
+ "compositePrimaryKeys": {},
+ "uniqueConstraints": {},
+ "checkConstraints": {}
+ },
+ "owner_admins": {
+ "name": "owner_admins",
+ "columns": {
+ "id": {
+ "name": "id",
+ "type": "text",
+ "primaryKey": true,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "email_digest": {
+ "name": "email_digest",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "account_id": {
+ "name": "account_id",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": false,
+ "autoincrement": false
+ },
+ "role": {
+ "name": "role",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": "'owner'"
+ },
+ "activated_at": {
+ "name": "activated_at",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": "CURRENT_TIMESTAMP"
+ },
+ "last_seen_at": {
+ "name": "last_seen_at",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": "CURRENT_TIMESTAMP"
+ }
+ },
+ "indexes": {
+ "owner_admins_email_digest_unique": {
+ "name": "owner_admins_email_digest_unique",
+ "columns": [
+ "email_digest"
+ ],
+ "isUnique": true
+ },
+ "owner_admins_account_id_unique": {
+ "name": "owner_admins_account_id_unique",
+ "columns": [
+ "account_id"
+ ],
+ "isUnique": true
+ }
+ },
+ "foreignKeys": {
+ "owner_admins_account_id_accounts_id_fk": {
+ "name": "owner_admins_account_id_accounts_id_fk",
+ "tableFrom": "owner_admins",
+ "tableTo": "accounts",
+ "columnsFrom": [
+ "account_id"
+ ],
+ "columnsTo": [
+ "id"
+ ],
+ "onDelete": "set null",
+ "onUpdate": "no action"
+ }
+ },
+ "compositePrimaryKeys": {},
+ "uniqueConstraints": {},
+ "checkConstraints": {}
+ },
+ "payment_records": {
+ "name": "payment_records",
+ "columns": {
+ "id": {
+ "name": "id",
+ "type": "text",
+ "primaryKey": true,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "vault_id": {
+ "name": "vault_id",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "debt_id": {
+ "name": "debt_id",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "scheduled_date": {
+ "name": "scheduled_date",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": false,
+ "autoincrement": false
+ },
+ "confirmed_at": {
+ "name": "confirmed_at",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "event_date": {
+ "name": "event_date",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": false,
+ "autoincrement": false
+ },
+ "cash_payment": {
+ "name": "cash_payment",
+ "type": "real",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "new_balance": {
+ "name": "new_balance",
+ "type": "real",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "source": {
+ "name": "source",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": "'self_report'"
+ },
+ "income_type": {
+ "name": "income_type",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": false,
+ "autoincrement": false
+ },
+ "created_at": {
+ "name": "created_at",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": "CURRENT_TIMESTAMP"
+ }
+ },
+ "indexes": {
+ "payments_vault_id_idx": {
+ "name": "payments_vault_id_idx",
+ "columns": [
+ "vault_id"
+ ],
+ "isUnique": false
+ },
+ "payments_debt_id_idx": {
+ "name": "payments_debt_id_idx",
+ "columns": [
+ "debt_id"
+ ],
+ "isUnique": false
+ }
+ },
+ "foreignKeys": {
+ "payment_records_vault_id_vaults_id_fk": {
+ "name": "payment_records_vault_id_vaults_id_fk",
+ "tableFrom": "payment_records",
+ "tableTo": "vaults",
+ "columnsFrom": [
+ "vault_id"
+ ],
+ "columnsTo": [
+ "id"
+ ],
+ "onDelete": "cascade",
+ "onUpdate": "no action"
+ },
+ "payment_records_debt_id_debts_id_fk": {
+ "name": "payment_records_debt_id_debts_id_fk",
+ "tableFrom": "payment_records",
+ "tableTo": "debts",
+ "columnsFrom": [
+ "debt_id"
+ ],
+ "columnsTo": [
+ "id"
+ ],
+ "onDelete": "cascade",
+ "onUpdate": "no action"
+ }
+ },
+ "compositePrimaryKeys": {},
+ "uniqueConstraints": {},
+ "checkConstraints": {}
+ },
+ "policy_acceptances": {
+ "name": "policy_acceptances",
+ "columns": {
+ "id": {
+ "name": "id",
+ "type": "text",
+ "primaryKey": true,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "vault_id": {
+ "name": "vault_id",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "policy_key": {
+ "name": "policy_key",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "policy_version": {
+ "name": "policy_version",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "accepted_at": {
+ "name": "accepted_at",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": "CURRENT_TIMESTAMP"
+ }
+ },
+ "indexes": {
+ "policy_acceptance_vault_key_version_unique": {
+ "name": "policy_acceptance_vault_key_version_unique",
+ "columns": [
+ "vault_id",
+ "policy_key",
+ "policy_version"
+ ],
+ "isUnique": true
+ },
+ "policy_acceptance_vault_idx": {
+ "name": "policy_acceptance_vault_idx",
+ "columns": [
+ "vault_id"
+ ],
+ "isUnique": false
+ }
+ },
+ "foreignKeys": {
+ "policy_acceptances_vault_id_vaults_id_fk": {
+ "name": "policy_acceptances_vault_id_vaults_id_fk",
+ "tableFrom": "policy_acceptances",
+ "tableTo": "vaults",
+ "columnsFrom": [
+ "vault_id"
+ ],
+ "columnsTo": [
+ "id"
+ ],
+ "onDelete": "cascade",
+ "onUpdate": "no action"
+ }
+ },
+ "compositePrimaryKeys": {},
+ "uniqueConstraints": {},
+ "checkConstraints": {}
+ },
+ "public_stories": {
+ "name": "public_stories",
+ "columns": {
+ "id": {
+ "name": "id",
+ "type": "text",
+ "primaryKey": true,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "vault_id": {
+ "name": "vault_id",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "debt_id": {
+ "name": "debt_id",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "anonymous_name": {
+ "name": "anonymous_name",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "country_code": {
+ "name": "country_code",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": "''"
+ },
+ "debt_kind": {
+ "name": "debt_kind",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "amount_band": {
+ "name": "amount_band",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "currency": {
+ "name": "currency",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "repayment_approach": {
+ "name": "repayment_approach",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": "'other'"
+ },
+ "story_text": {
+ "name": "story_text",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "status": {
+ "name": "status",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": "'pending'"
+ },
+ "created_at": {
+ "name": "created_at",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": "CURRENT_TIMESTAMP"
+ },
+ "updated_at": {
+ "name": "updated_at",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": "CURRENT_TIMESTAMP"
+ }
+ },
+ "indexes": {
+ "public_stories_status_idx": {
+ "name": "public_stories_status_idx",
+ "columns": [
+ "status"
+ ],
+ "isUnique": false
+ },
+ "public_stories_vault_idx": {
+ "name": "public_stories_vault_idx",
+ "columns": [
+ "vault_id"
+ ],
+ "isUnique": false
+ }
+ },
+ "foreignKeys": {
+ "public_stories_vault_id_vaults_id_fk": {
+ "name": "public_stories_vault_id_vaults_id_fk",
+ "tableFrom": "public_stories",
+ "tableTo": "vaults",
+ "columnsFrom": [
+ "vault_id"
+ ],
+ "columnsTo": [
+ "id"
+ ],
+ "onDelete": "cascade",
+ "onUpdate": "no action"
+ },
+ "public_stories_debt_id_debts_id_fk": {
+ "name": "public_stories_debt_id_debts_id_fk",
+ "tableFrom": "public_stories",
+ "tableTo": "debts",
+ "columnsFrom": [
+ "debt_id"
+ ],
+ "columnsTo": [
+ "id"
+ ],
+ "onDelete": "cascade",
+ "onUpdate": "no action"
+ }
+ },
+ "compositePrimaryKeys": {},
+ "uniqueConstraints": {},
+ "checkConstraints": {}
+ },
+ "referral_codes": {
+ "name": "referral_codes",
+ "columns": {
+ "id": {
+ "name": "id",
+ "type": "text",
+ "primaryKey": true,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "vault_id": {
+ "name": "vault_id",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "code": {
+ "name": "code",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "status": {
+ "name": "status",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": "'active'"
+ },
+ "created_at": {
+ "name": "created_at",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": "CURRENT_TIMESTAMP"
+ }
+ },
+ "indexes": {
+ "referral_codes_vault_id_unique": {
+ "name": "referral_codes_vault_id_unique",
+ "columns": [
+ "vault_id"
+ ],
+ "isUnique": true
+ },
+ "referral_codes_code_unique": {
+ "name": "referral_codes_code_unique",
+ "columns": [
+ "code"
+ ],
+ "isUnique": true
+ },
+ "referral_codes_status_idx": {
+ "name": "referral_codes_status_idx",
+ "columns": [
+ "status"
+ ],
+ "isUnique": false
+ }
+ },
+ "foreignKeys": {
+ "referral_codes_vault_id_vaults_id_fk": {
+ "name": "referral_codes_vault_id_vaults_id_fk",
+ "tableFrom": "referral_codes",
+ "tableTo": "vaults",
+ "columnsFrom": [
+ "vault_id"
+ ],
+ "columnsTo": [
+ "id"
+ ],
+ "onDelete": "cascade",
+ "onUpdate": "no action"
+ }
+ },
+ "compositePrimaryKeys": {},
+ "uniqueConstraints": {},
+ "checkConstraints": {}
+ },
+ "referral_relationships": {
+ "name": "referral_relationships",
+ "columns": {
+ "id": {
+ "name": "id",
+ "type": "text",
+ "primaryKey": true,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "inviter_vault_id": {
+ "name": "inviter_vault_id",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "invited_vault_id": {
+ "name": "invited_vault_id",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "code_id": {
+ "name": "code_id",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "status": {
+ "name": "status",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": "'pending'"
+ },
+ "qualified_at": {
+ "name": "qualified_at",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": false,
+ "autoincrement": false
+ },
+ "rewarded_at": {
+ "name": "rewarded_at",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": false,
+ "autoincrement": false
+ },
+ "created_at": {
+ "name": "created_at",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": "CURRENT_TIMESTAMP"
+ }
+ },
+ "indexes": {
+ "referral_relationships_invited_vault_id_unique": {
+ "name": "referral_relationships_invited_vault_id_unique",
+ "columns": [
+ "invited_vault_id"
+ ],
+ "isUnique": true
+ },
+ "referrals_inviter_status_idx": {
+ "name": "referrals_inviter_status_idx",
+ "columns": [
+ "inviter_vault_id",
+ "status"
+ ],
+ "isUnique": false
+ },
+ "referrals_created_idx": {
+ "name": "referrals_created_idx",
+ "columns": [
+ "created_at"
+ ],
+ "isUnique": false
+ }
+ },
+ "foreignKeys": {
+ "referral_relationships_inviter_vault_id_vaults_id_fk": {
+ "name": "referral_relationships_inviter_vault_id_vaults_id_fk",
+ "tableFrom": "referral_relationships",
+ "tableTo": "vaults",
+ "columnsFrom": [
+ "inviter_vault_id"
+ ],
+ "columnsTo": [
+ "id"
+ ],
+ "onDelete": "cascade",
+ "onUpdate": "no action"
+ },
+ "referral_relationships_invited_vault_id_vaults_id_fk": {
+ "name": "referral_relationships_invited_vault_id_vaults_id_fk",
+ "tableFrom": "referral_relationships",
+ "tableTo": "vaults",
+ "columnsFrom": [
+ "invited_vault_id"
+ ],
+ "columnsTo": [
+ "id"
+ ],
+ "onDelete": "cascade",
+ "onUpdate": "no action"
+ },
+ "referral_relationships_code_id_referral_codes_id_fk": {
+ "name": "referral_relationships_code_id_referral_codes_id_fk",
+ "tableFrom": "referral_relationships",
+ "tableTo": "referral_codes",
+ "columnsFrom": [
+ "code_id"
+ ],
+ "columnsTo": [
+ "id"
+ ],
+ "onDelete": "cascade",
+ "onUpdate": "no action"
+ }
+ },
+ "compositePrimaryKeys": {},
+ "uniqueConstraints": {},
+ "checkConstraints": {}
+ },
+ "shore_value_ledger": {
+ "name": "shore_value_ledger",
+ "columns": {
+ "id": {
+ "name": "id",
+ "type": "text",
+ "primaryKey": true,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "vault_id": {
+ "name": "vault_id",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "event_key": {
+ "name": "event_key",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "event_type": {
+ "name": "event_type",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "points": {
+ "name": "points",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "reference_id": {
+ "name": "reference_id",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": false,
+ "autoincrement": false
+ },
+ "created_at": {
+ "name": "created_at",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": "CURRENT_TIMESTAMP"
+ }
+ },
+ "indexes": {
+ "shore_value_ledger_event_key_unique": {
+ "name": "shore_value_ledger_event_key_unique",
+ "columns": [
+ "event_key"
+ ],
+ "isUnique": true
+ },
+ "shore_value_vault_created_idx": {
+ "name": "shore_value_vault_created_idx",
+ "columns": [
+ "vault_id",
+ "created_at"
+ ],
+ "isUnique": false
+ },
+ "shore_value_event_type_idx": {
+ "name": "shore_value_event_type_idx",
+ "columns": [
+ "event_type"
+ ],
+ "isUnique": false
+ }
+ },
+ "foreignKeys": {
+ "shore_value_ledger_vault_id_vaults_id_fk": {
+ "name": "shore_value_ledger_vault_id_vaults_id_fk",
+ "tableFrom": "shore_value_ledger",
+ "tableTo": "vaults",
+ "columnsFrom": [
+ "vault_id"
+ ],
+ "columnsTo": [
+ "id"
+ ],
+ "onDelete": "cascade",
+ "onUpdate": "no action"
+ }
+ },
+ "compositePrimaryKeys": {},
+ "uniqueConstraints": {},
+ "checkConstraints": {}
+ },
+ "starlight_gifts": {
+ "name": "starlight_gifts",
+ "columns": {
+ "id": {
+ "name": "id",
+ "type": "text",
+ "primaryKey": true,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "sender_vault_id": {
+ "name": "sender_vault_id",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "recipient_vault_id": {
+ "name": "recipient_vault_id",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "story_id": {
+ "name": "story_id",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": false,
+ "autoincrement": false
+ },
+ "points": {
+ "name": "points",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "gift_date": {
+ "name": "gift_date",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "idempotency_key": {
+ "name": "idempotency_key",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "created_at": {
+ "name": "created_at",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": "CURRENT_TIMESTAMP"
+ }
+ },
+ "indexes": {
+ "starlight_gifts_idempotency_key_unique": {
+ "name": "starlight_gifts_idempotency_key_unique",
+ "columns": [
+ "idempotency_key"
+ ],
+ "isUnique": true
+ },
+ "starlight_sender_created_idx": {
+ "name": "starlight_sender_created_idx",
+ "columns": [
+ "sender_vault_id",
+ "created_at"
+ ],
+ "isUnique": false
+ },
+ "starlight_recipient_created_idx": {
+ "name": "starlight_recipient_created_idx",
+ "columns": [
+ "recipient_vault_id",
+ "created_at"
+ ],
+ "isUnique": false
+ }
+ },
+ "foreignKeys": {
+ "starlight_gifts_sender_vault_id_vaults_id_fk": {
+ "name": "starlight_gifts_sender_vault_id_vaults_id_fk",
+ "tableFrom": "starlight_gifts",
+ "tableTo": "vaults",
+ "columnsFrom": [
+ "sender_vault_id"
+ ],
+ "columnsTo": [
+ "id"
+ ],
+ "onDelete": "cascade",
+ "onUpdate": "no action"
+ },
+ "starlight_gifts_recipient_vault_id_vaults_id_fk": {
+ "name": "starlight_gifts_recipient_vault_id_vaults_id_fk",
+ "tableFrom": "starlight_gifts",
+ "tableTo": "vaults",
+ "columnsFrom": [
+ "recipient_vault_id"
+ ],
+ "columnsTo": [
+ "id"
+ ],
+ "onDelete": "cascade",
+ "onUpdate": "no action"
+ }
+ },
+ "compositePrimaryKeys": {},
+ "uniqueConstraints": {},
+ "checkConstraints": {}
+ },
+ "starlight_wallets": {
+ "name": "starlight_wallets",
+ "columns": {
+ "vault_id": {
+ "name": "vault_id",
+ "type": "text",
+ "primaryKey": true,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "available": {
+ "name": "available",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": 0
+ },
+ "lifetime_earned": {
+ "name": "lifetime_earned",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": 0
+ },
+ "lifetime_sent": {
+ "name": "lifetime_sent",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": 0
+ },
+ "lifetime_received": {
+ "name": "lifetime_received",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": 0
+ },
+ "updated_at": {
+ "name": "updated_at",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": "CURRENT_TIMESTAMP"
+ }
+ },
+ "indexes": {},
+ "foreignKeys": {
+ "starlight_wallets_vault_id_vaults_id_fk": {
+ "name": "starlight_wallets_vault_id_vaults_id_fk",
+ "tableFrom": "starlight_wallets",
+ "tableTo": "vaults",
+ "columnsFrom": [
+ "vault_id"
+ ],
+ "columnsTo": [
+ "id"
+ ],
+ "onDelete": "cascade",
+ "onUpdate": "no action"
+ }
+ },
+ "compositePrimaryKeys": {},
+ "uniqueConstraints": {},
+ "checkConstraints": {}
+ },
+ "story_encouragements": {
+ "name": "story_encouragements",
+ "columns": {
+ "id": {
+ "name": "id",
+ "type": "text",
+ "primaryKey": true,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "story_id": {
+ "name": "story_id",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "vault_id": {
+ "name": "vault_id",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "created_at": {
+ "name": "created_at",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": "CURRENT_TIMESTAMP"
+ }
+ },
+ "indexes": {
+ "story_encouragement_unique": {
+ "name": "story_encouragement_unique",
+ "columns": [
+ "story_id",
+ "vault_id"
+ ],
+ "isUnique": true
+ },
+ "story_encouragement_story_idx": {
+ "name": "story_encouragement_story_idx",
+ "columns": [
+ "story_id"
+ ],
+ "isUnique": false
+ }
+ },
+ "foreignKeys": {
+ "story_encouragements_story_id_public_stories_id_fk": {
+ "name": "story_encouragements_story_id_public_stories_id_fk",
+ "tableFrom": "story_encouragements",
+ "tableTo": "public_stories",
+ "columnsFrom": [
+ "story_id"
+ ],
+ "columnsTo": [
+ "id"
+ ],
+ "onDelete": "cascade",
+ "onUpdate": "no action"
+ },
+ "story_encouragements_vault_id_vaults_id_fk": {
+ "name": "story_encouragements_vault_id_vaults_id_fk",
+ "tableFrom": "story_encouragements",
+ "tableTo": "vaults",
+ "columnsFrom": [
+ "vault_id"
+ ],
+ "columnsTo": [
+ "id"
+ ],
+ "onDelete": "cascade",
+ "onUpdate": "no action"
+ }
+ },
+ "compositePrimaryKeys": {},
+ "uniqueConstraints": {},
+ "checkConstraints": {}
+ },
+ "story_reports": {
+ "name": "story_reports",
+ "columns": {
+ "id": {
+ "name": "id",
+ "type": "text",
+ "primaryKey": true,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "story_id": {
+ "name": "story_id",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "reporter_vault_id": {
+ "name": "reporter_vault_id",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "reason": {
+ "name": "reason",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "details": {
+ "name": "details",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": "''"
+ },
+ "status": {
+ "name": "status",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": "'open'"
+ },
+ "created_at": {
+ "name": "created_at",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": "CURRENT_TIMESTAMP"
+ },
+ "resolved_at": {
+ "name": "resolved_at",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": false,
+ "autoincrement": false
+ }
+ },
+ "indexes": {
+ "story_report_unique": {
+ "name": "story_report_unique",
+ "columns": [
+ "story_id",
+ "reporter_vault_id"
+ ],
+ "isUnique": true
+ },
+ "story_reports_status_idx": {
+ "name": "story_reports_status_idx",
+ "columns": [
+ "status"
+ ],
+ "isUnique": false
+ }
+ },
+ "foreignKeys": {
+ "story_reports_story_id_public_stories_id_fk": {
+ "name": "story_reports_story_id_public_stories_id_fk",
+ "tableFrom": "story_reports",
+ "tableTo": "public_stories",
+ "columnsFrom": [
+ "story_id"
+ ],
+ "columnsTo": [
+ "id"
+ ],
+ "onDelete": "cascade",
+ "onUpdate": "no action"
+ },
+ "story_reports_reporter_vault_id_vaults_id_fk": {
+ "name": "story_reports_reporter_vault_id_vaults_id_fk",
+ "tableFrom": "story_reports",
+ "tableTo": "vaults",
+ "columnsFrom": [
+ "reporter_vault_id"
+ ],
+ "columnsTo": [
+ "id"
+ ],
+ "onDelete": "cascade",
+ "onUpdate": "no action"
+ }
+ },
+ "compositePrimaryKeys": {},
+ "uniqueConstraints": {},
+ "checkConstraints": {}
+ },
+ "vaults": {
+ "name": "vaults",
+ "columns": {
+ "id": {
+ "name": "id",
+ "type": "text",
+ "primaryKey": true,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "recovery_hash": {
+ "name": "recovery_hash",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "alias": {
+ "name": "alias",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "region": {
+ "name": "region",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "pressure": {
+ "name": "pressure",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": "''"
+ },
+ "age_band": {
+ "name": "age_band",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": "''"
+ },
+ "gender": {
+ "name": "gender",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": "''"
+ },
+ "mbti": {
+ "name": "mbti",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": "''"
+ },
+ "zodiac": {
+ "name": "zodiac",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": "''"
+ },
+ "self_description": {
+ "name": "self_description",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": "''"
+ },
+ "repayment_plan": {
+ "name": "repayment_plan",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": "''"
+ },
+ "repayment_outlook": {
+ "name": "repayment_outlook",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": "''"
+ },
+ "income_plan": {
+ "name": "income_plan",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": "''"
+ },
+ "position_x": {
+ "name": "position_x",
+ "type": "real",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": 47
+ },
+ "position_y": {
+ "name": "position_y",
+ "type": "real",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": 63
+ },
+ "locale": {
+ "name": "locale",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": "'zh'"
+ },
+ "country_code": {
+ "name": "country_code",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": "''"
+ },
+ "country_name": {
+ "name": "country_name",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": "''"
+ },
+ "display_currency": {
+ "name": "display_currency",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": "'CNY'"
+ },
+ "monthly_income": {
+ "name": "monthly_income",
+ "type": "real",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": 0
+ },
+ "monthly_expenses": {
+ "name": "monthly_expenses",
+ "type": "real",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": 0
+ },
+ "discovery_consent": {
+ "name": "discovery_consent",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": false
+ },
+ "created_at": {
+ "name": "created_at",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": "CURRENT_TIMESTAMP"
+ },
+ "updated_at": {
+ "name": "updated_at",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": "CURRENT_TIMESTAMP"
+ }
+ },
+ "indexes": {
+ "vaults_recovery_hash_unique": {
+ "name": "vaults_recovery_hash_unique",
+ "columns": [
+ "recovery_hash"
+ ],
+ "isUnique": true
+ }
+ },
+ "foreignKeys": {},
+ "compositePrimaryKeys": {},
+ "uniqueConstraints": {},
+ "checkConstraints": {}
+ },
+ "world_category_candidates": {
+ "name": "world_category_candidates",
+ "columns": {
+ "id": {
+ "name": "id",
+ "type": "text",
+ "primaryKey": true,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "canonical_key": {
+ "name": "canonical_key",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "parent_kind": {
+ "name": "parent_kind",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": "'other'"
+ },
+ "name_zh": {
+ "name": "name_zh",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "name_en": {
+ "name": "name_en",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "description_zh": {
+ "name": "description_zh",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": "''"
+ },
+ "description_en": {
+ "name": "description_en",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": "''"
+ },
+ "status": {
+ "name": "status",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": "'candidate'"
+ },
+ "stage": {
+ "name": "stage",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": 0
+ },
+ "confidence": {
+ "name": "confidence",
+ "type": "real",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": 0
+ },
+ "unique_vaults": {
+ "name": "unique_vaults",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": 0
+ },
+ "region_count": {
+ "name": "region_count",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": 0
+ },
+ "mention_count": {
+ "name": "mention_count",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": 0
+ },
+ "emergence_score": {
+ "name": "emergence_score",
+ "type": "real",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": 0
+ },
+ "weight_profile_id": {
+ "name": "weight_profile_id",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": false,
+ "autoincrement": false
+ },
+ "merged_into_id": {
+ "name": "merged_into_id",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": false,
+ "autoincrement": false
+ },
+ "proposed_at": {
+ "name": "proposed_at",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": "CURRENT_TIMESTAMP"
+ },
+ "reviewed_at": {
+ "name": "reviewed_at",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": false,
+ "autoincrement": false
+ },
+ "published_at": {
+ "name": "published_at",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": false,
+ "autoincrement": false
+ },
+ "updated_at": {
+ "name": "updated_at",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": "CURRENT_TIMESTAMP"
+ }
+ },
+ "indexes": {
+ "world_category_candidates_canonical_key_unique": {
+ "name": "world_category_candidates_canonical_key_unique",
+ "columns": [
+ "canonical_key"
+ ],
+ "isUnique": true
+ },
+ "world_candidates_status_idx": {
+ "name": "world_candidates_status_idx",
+ "columns": [
+ "status"
+ ],
+ "isUnique": false
+ },
+ "world_candidates_score_idx": {
+ "name": "world_candidates_score_idx",
+ "columns": [
+ "emergence_score"
+ ],
+ "isUnique": false
+ }
+ },
+ "foreignKeys": {
+ "world_category_candidates_weight_profile_id_world_weight_profiles_id_fk": {
+ "name": "world_category_candidates_weight_profile_id_world_weight_profiles_id_fk",
+ "tableFrom": "world_category_candidates",
+ "tableTo": "world_weight_profiles",
+ "columnsFrom": [
+ "weight_profile_id"
+ ],
+ "columnsTo": [
+ "id"
+ ],
+ "onDelete": "no action",
+ "onUpdate": "no action"
+ }
+ },
+ "compositePrimaryKeys": {},
+ "uniqueConstraints": {},
+ "checkConstraints": {}
+ },
+ "world_growth_events": {
+ "name": "world_growth_events",
+ "columns": {
+ "id": {
+ "name": "id",
+ "type": "text",
+ "primaryKey": true,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "candidate_id": {
+ "name": "candidate_id",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "event_type": {
+ "name": "event_type",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "from_stage": {
+ "name": "from_stage",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": false,
+ "autoincrement": false
+ },
+ "to_stage": {
+ "name": "to_stage",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": false,
+ "autoincrement": false
+ },
+ "actor_type": {
+ "name": "actor_type",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": "'system'"
+ },
+ "weight_profile_id": {
+ "name": "weight_profile_id",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": false,
+ "autoincrement": false
+ },
+ "evidence_json": {
+ "name": "evidence_json",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": "'{}'"
+ },
+ "reason": {
+ "name": "reason",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": "''"
+ },
+ "created_at": {
+ "name": "created_at",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": "CURRENT_TIMESTAMP"
+ }
+ },
+ "indexes": {
+ "world_events_candidate_idx": {
+ "name": "world_events_candidate_idx",
+ "columns": [
+ "candidate_id"
+ ],
+ "isUnique": false
+ }
+ },
+ "foreignKeys": {
+ "world_growth_events_candidate_id_world_category_candidates_id_fk": {
+ "name": "world_growth_events_candidate_id_world_category_candidates_id_fk",
+ "tableFrom": "world_growth_events",
+ "tableTo": "world_category_candidates",
+ "columnsFrom": [
+ "candidate_id"
+ ],
+ "columnsTo": [
+ "id"
+ ],
+ "onDelete": "cascade",
+ "onUpdate": "no action"
+ },
+ "world_growth_events_weight_profile_id_world_weight_profiles_id_fk": {
+ "name": "world_growth_events_weight_profile_id_world_weight_profiles_id_fk",
+ "tableFrom": "world_growth_events",
+ "tableTo": "world_weight_profiles",
+ "columnsFrom": [
+ "weight_profile_id"
+ ],
+ "columnsTo": [
+ "id"
+ ],
+ "onDelete": "no action",
+ "onUpdate": "no action"
+ }
+ },
+ "compositePrimaryKeys": {},
+ "uniqueConstraints": {},
+ "checkConstraints": {}
+ },
+ "world_signal_assignments": {
+ "name": "world_signal_assignments",
+ "columns": {
+ "id": {
+ "name": "id",
+ "type": "text",
+ "primaryKey": true,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "vault_id": {
+ "name": "vault_id",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "debt_id": {
+ "name": "debt_id",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "candidate_id": {
+ "name": "candidate_id",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "confidence": {
+ "name": "confidence",
+ "type": "real",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "assignment_source": {
+ "name": "assignment_source",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": "'ai'"
+ },
+ "taxonomy_version": {
+ "name": "taxonomy_version",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": 1
+ },
+ "created_at": {
+ "name": "created_at",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": "CURRENT_TIMESTAMP"
+ },
+ "updated_at": {
+ "name": "updated_at",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": "CURRENT_TIMESTAMP"
+ }
+ },
+ "indexes": {
+ "world_signal_assignments_debt_id_unique": {
+ "name": "world_signal_assignments_debt_id_unique",
+ "columns": [
+ "debt_id"
+ ],
+ "isUnique": true
+ },
+ "world_signals_vault_idx": {
+ "name": "world_signals_vault_idx",
+ "columns": [
+ "vault_id"
+ ],
+ "isUnique": false
+ },
+ "world_signals_candidate_idx": {
+ "name": "world_signals_candidate_idx",
+ "columns": [
+ "candidate_id"
+ ],
+ "isUnique": false
+ }
+ },
+ "foreignKeys": {
+ "world_signal_assignments_vault_id_vaults_id_fk": {
+ "name": "world_signal_assignments_vault_id_vaults_id_fk",
+ "tableFrom": "world_signal_assignments",
+ "tableTo": "vaults",
+ "columnsFrom": [
+ "vault_id"
+ ],
+ "columnsTo": [
+ "id"
+ ],
+ "onDelete": "cascade",
+ "onUpdate": "no action"
+ },
+ "world_signal_assignments_debt_id_debts_id_fk": {
+ "name": "world_signal_assignments_debt_id_debts_id_fk",
+ "tableFrom": "world_signal_assignments",
+ "tableTo": "debts",
+ "columnsFrom": [
+ "debt_id"
+ ],
+ "columnsTo": [
+ "id"
+ ],
+ "onDelete": "cascade",
+ "onUpdate": "no action"
+ },
+ "world_signal_assignments_candidate_id_world_category_candidates_id_fk": {
+ "name": "world_signal_assignments_candidate_id_world_category_candidates_id_fk",
+ "tableFrom": "world_signal_assignments",
+ "tableTo": "world_category_candidates",
+ "columnsFrom": [
+ "candidate_id"
+ ],
+ "columnsTo": [
+ "id"
+ ],
+ "onDelete": "cascade",
+ "onUpdate": "no action"
+ }
+ },
+ "compositePrimaryKeys": {},
+ "uniqueConstraints": {},
+ "checkConstraints": {}
+ },
+ "world_weight_profiles": {
+ "name": "world_weight_profiles",
+ "columns": {
+ "id": {
+ "name": "id",
+ "type": "text",
+ "primaryKey": true,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "version": {
+ "name": "version",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "status": {
+ "name": "status",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": "'draft'"
+ },
+ "frequency_weight": {
+ "name": "frequency_weight",
+ "type": "real",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "growth_weight": {
+ "name": "growth_weight",
+ "type": "real",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "geography_weight": {
+ "name": "geography_weight",
+ "type": "real",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "recurrence_weight": {
+ "name": "recurrence_weight",
+ "type": "real",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "connection_weight": {
+ "name": "connection_weight",
+ "type": "real",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "quality_weight": {
+ "name": "quality_weight",
+ "type": "real",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "proposed_by": {
+ "name": "proposed_by",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": "'human'"
+ },
+ "model_ref": {
+ "name": "model_ref",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": false,
+ "autoincrement": false
+ },
+ "rationale": {
+ "name": "rationale",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": "''"
+ },
+ "created_at": {
+ "name": "created_at",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": "CURRENT_TIMESTAMP"
+ },
+ "activated_at": {
+ "name": "activated_at",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": false,
+ "autoincrement": false
+ }
+ },
+ "indexes": {
+ "world_weight_profiles_version_unique": {
+ "name": "world_weight_profiles_version_unique",
+ "columns": [
+ "version"
+ ],
+ "isUnique": true
+ }
+ },
+ "foreignKeys": {},
+ "compositePrimaryKeys": {},
+ "uniqueConstraints": {},
+ "checkConstraints": {}
+ }
+ },
+ "views": {},
+ "enums": {},
+ "_meta": {
+ "schemas": {},
+ "tables": {},
+ "columns": {}
+ },
+ "internal": {
+ "indexes": {}
+ }
+}
diff --git a/drizzle/meta/0017_snapshot.json b/drizzle/meta/0017_snapshot.json
new file mode 100644
index 0000000..8a7de5d
--- /dev/null
+++ b/drizzle/meta/0017_snapshot.json
@@ -0,0 +1,3149 @@
+{
+ "version": "6",
+ "dialect": "sqlite",
+ "id": "6ba4444a-29a5-48ef-b379-bf07388337ca",
+ "prevId": "5edb23cb-cd2c-44d2-82b0-d875d54a29bc",
+ "tables": {
+ "account_auth_limits": {
+ "name": "account_auth_limits",
+ "columns": {
+ "limit_key": {
+ "name": "limit_key",
+ "type": "text",
+ "primaryKey": true,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "action": {
+ "name": "action",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "window_key": {
+ "name": "window_key",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "attempts": {
+ "name": "attempts",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": 0
+ },
+ "updated_at": {
+ "name": "updated_at",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": "CURRENT_TIMESTAMP"
+ }
+ },
+ "indexes": {
+ "account_auth_limits_window_idx": {
+ "name": "account_auth_limits_window_idx",
+ "columns": [
+ "window_key"
+ ],
+ "isUnique": false
+ }
+ },
+ "foreignKeys": {},
+ "compositePrimaryKeys": {},
+ "uniqueConstraints": {},
+ "checkConstraints": {}
+ },
+ "account_sessions": {
+ "name": "account_sessions",
+ "columns": {
+ "id": {
+ "name": "id",
+ "type": "text",
+ "primaryKey": true,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "account_id": {
+ "name": "account_id",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "token_hash": {
+ "name": "token_hash",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "expires_at": {
+ "name": "expires_at",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "created_at": {
+ "name": "created_at",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": "CURRENT_TIMESTAMP"
+ },
+ "last_seen_at": {
+ "name": "last_seen_at",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": "CURRENT_TIMESTAMP"
+ }
+ },
+ "indexes": {
+ "account_sessions_token_hash_unique": {
+ "name": "account_sessions_token_hash_unique",
+ "columns": [
+ "token_hash"
+ ],
+ "isUnique": true
+ },
+ "account_sessions_account_idx": {
+ "name": "account_sessions_account_idx",
+ "columns": [
+ "account_id"
+ ],
+ "isUnique": false
+ },
+ "account_sessions_expires_idx": {
+ "name": "account_sessions_expires_idx",
+ "columns": [
+ "expires_at"
+ ],
+ "isUnique": false
+ }
+ },
+ "foreignKeys": {
+ "account_sessions_account_id_accounts_id_fk": {
+ "name": "account_sessions_account_id_accounts_id_fk",
+ "tableFrom": "account_sessions",
+ "tableTo": "accounts",
+ "columnsFrom": [
+ "account_id"
+ ],
+ "columnsTo": [
+ "id"
+ ],
+ "onDelete": "cascade",
+ "onUpdate": "no action"
+ }
+ },
+ "compositePrimaryKeys": {},
+ "uniqueConstraints": {},
+ "checkConstraints": {}
+ },
+ "account_vaults": {
+ "name": "account_vaults",
+ "columns": {
+ "account_id": {
+ "name": "account_id",
+ "type": "text",
+ "primaryKey": true,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "vault_id": {
+ "name": "vault_id",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "linked_at": {
+ "name": "linked_at",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": "CURRENT_TIMESTAMP"
+ }
+ },
+ "indexes": {
+ "account_vaults_vault_id_unique": {
+ "name": "account_vaults_vault_id_unique",
+ "columns": [
+ "vault_id"
+ ],
+ "isUnique": true
+ },
+ "account_vaults_vault_idx": {
+ "name": "account_vaults_vault_idx",
+ "columns": [
+ "vault_id"
+ ],
+ "isUnique": false
+ }
+ },
+ "foreignKeys": {
+ "account_vaults_account_id_accounts_id_fk": {
+ "name": "account_vaults_account_id_accounts_id_fk",
+ "tableFrom": "account_vaults",
+ "tableTo": "accounts",
+ "columnsFrom": [
+ "account_id"
+ ],
+ "columnsTo": [
+ "id"
+ ],
+ "onDelete": "cascade",
+ "onUpdate": "no action"
+ },
+ "account_vaults_vault_id_vaults_id_fk": {
+ "name": "account_vaults_vault_id_vaults_id_fk",
+ "tableFrom": "account_vaults",
+ "tableTo": "vaults",
+ "columnsFrom": [
+ "vault_id"
+ ],
+ "columnsTo": [
+ "id"
+ ],
+ "onDelete": "cascade",
+ "onUpdate": "no action"
+ }
+ },
+ "compositePrimaryKeys": {},
+ "uniqueConstraints": {},
+ "checkConstraints": {}
+ },
+ "accounts": {
+ "name": "accounts",
+ "columns": {
+ "id": {
+ "name": "id",
+ "type": "text",
+ "primaryKey": true,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "user_code": {
+ "name": "user_code",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "username": {
+ "name": "username",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "username_normalized": {
+ "name": "username_normalized",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "password_hash": {
+ "name": "password_hash",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "password_salt": {
+ "name": "password_salt",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "password_iterations": {
+ "name": "password_iterations",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "status": {
+ "name": "status",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": "'active'"
+ },
+ "signup_source": {
+ "name": "signup_source",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": "'direct'"
+ },
+ "created_at": {
+ "name": "created_at",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": "CURRENT_TIMESTAMP"
+ },
+ "updated_at": {
+ "name": "updated_at",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": "CURRENT_TIMESTAMP"
+ },
+ "last_login_at": {
+ "name": "last_login_at",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": false,
+ "autoincrement": false
+ },
+ "last_seen_at": {
+ "name": "last_seen_at",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": false,
+ "autoincrement": false
+ }
+ },
+ "indexes": {
+ "accounts_user_code_unique": {
+ "name": "accounts_user_code_unique",
+ "columns": [
+ "user_code"
+ ],
+ "isUnique": true
+ },
+ "accounts_username_normalized_unique": {
+ "name": "accounts_username_normalized_unique",
+ "columns": [
+ "username_normalized"
+ ],
+ "isUnique": true
+ },
+ "accounts_created_idx": {
+ "name": "accounts_created_idx",
+ "columns": [
+ "created_at"
+ ],
+ "isUnique": false
+ }
+ },
+ "foreignKeys": {},
+ "compositePrimaryKeys": {},
+ "uniqueConstraints": {},
+ "checkConstraints": {}
+ },
+ "ai_daily_usage": {
+ "name": "ai_daily_usage",
+ "columns": {
+ "id": {
+ "name": "id",
+ "type": "text",
+ "primaryKey": true,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "vault_id": {
+ "name": "vault_id",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "usage_date": {
+ "name": "usage_date",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "request_count": {
+ "name": "request_count",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": 0
+ },
+ "input_tokens": {
+ "name": "input_tokens",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": 0
+ },
+ "output_tokens": {
+ "name": "output_tokens",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": 0
+ },
+ "updated_at": {
+ "name": "updated_at",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": "CURRENT_TIMESTAMP"
+ }
+ },
+ "indexes": {
+ "ai_daily_usage_vault_date_unique": {
+ "name": "ai_daily_usage_vault_date_unique",
+ "columns": [
+ "vault_id",
+ "usage_date"
+ ],
+ "isUnique": true
+ },
+ "ai_daily_usage_date_idx": {
+ "name": "ai_daily_usage_date_idx",
+ "columns": [
+ "usage_date"
+ ],
+ "isUnique": false
+ }
+ },
+ "foreignKeys": {
+ "ai_daily_usage_vault_id_vaults_id_fk": {
+ "name": "ai_daily_usage_vault_id_vaults_id_fk",
+ "tableFrom": "ai_daily_usage",
+ "tableTo": "vaults",
+ "columnsFrom": [
+ "vault_id"
+ ],
+ "columnsTo": [
+ "id"
+ ],
+ "onDelete": "cascade",
+ "onUpdate": "no action"
+ }
+ },
+ "compositePrimaryKeys": {},
+ "uniqueConstraints": {},
+ "checkConstraints": {}
+ },
+ "beta_enrollments": {
+ "name": "beta_enrollments",
+ "columns": {
+ "id": {
+ "name": "id",
+ "type": "text",
+ "primaryKey": true,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "vault_id": {
+ "name": "vault_id",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "invite_digest": {
+ "name": "invite_digest",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "consent_version": {
+ "name": "consent_version",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "created_at": {
+ "name": "created_at",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": "CURRENT_TIMESTAMP"
+ }
+ },
+ "indexes": {
+ "beta_enrollments_vault_id_unique": {
+ "name": "beta_enrollments_vault_id_unique",
+ "columns": [
+ "vault_id"
+ ],
+ "isUnique": true
+ },
+ "beta_enrollments_created_idx": {
+ "name": "beta_enrollments_created_idx",
+ "columns": [
+ "created_at"
+ ],
+ "isUnique": false
+ }
+ },
+ "foreignKeys": {
+ "beta_enrollments_vault_id_vaults_id_fk": {
+ "name": "beta_enrollments_vault_id_vaults_id_fk",
+ "tableFrom": "beta_enrollments",
+ "tableTo": "vaults",
+ "columnsFrom": [
+ "vault_id"
+ ],
+ "columnsTo": [
+ "id"
+ ],
+ "onDelete": "cascade",
+ "onUpdate": "no action"
+ }
+ },
+ "compositePrimaryKeys": {},
+ "uniqueConstraints": {},
+ "checkConstraints": {}
+ },
+ "beta_feedback": {
+ "name": "beta_feedback",
+ "columns": {
+ "id": {
+ "name": "id",
+ "type": "text",
+ "primaryKey": true,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "vault_id": {
+ "name": "vault_id",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "category": {
+ "name": "category",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "rating": {
+ "name": "rating",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "message": {
+ "name": "message",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "page_path": {
+ "name": "page_path",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": "'/'"
+ },
+ "status": {
+ "name": "status",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": "'open'"
+ },
+ "created_at": {
+ "name": "created_at",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": "CURRENT_TIMESTAMP"
+ },
+ "resolved_at": {
+ "name": "resolved_at",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": false,
+ "autoincrement": false
+ }
+ },
+ "indexes": {
+ "beta_feedback_vault_idx": {
+ "name": "beta_feedback_vault_idx",
+ "columns": [
+ "vault_id"
+ ],
+ "isUnique": false
+ },
+ "beta_feedback_status_idx": {
+ "name": "beta_feedback_status_idx",
+ "columns": [
+ "status"
+ ],
+ "isUnique": false
+ }
+ },
+ "foreignKeys": {
+ "beta_feedback_vault_id_vaults_id_fk": {
+ "name": "beta_feedback_vault_id_vaults_id_fk",
+ "tableFrom": "beta_feedback",
+ "tableTo": "vaults",
+ "columnsFrom": [
+ "vault_id"
+ ],
+ "columnsTo": [
+ "id"
+ ],
+ "onDelete": "cascade",
+ "onUpdate": "no action"
+ }
+ },
+ "compositePrimaryKeys": {},
+ "uniqueConstraints": {},
+ "checkConstraints": {}
+ },
+ "beta_invite_counters": {
+ "name": "beta_invite_counters",
+ "columns": {
+ "invite_digest": {
+ "name": "invite_digest",
+ "type": "text",
+ "primaryKey": true,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "uses": {
+ "name": "uses",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": 0
+ },
+ "max_uses": {
+ "name": "max_uses",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "updated_at": {
+ "name": "updated_at",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": "CURRENT_TIMESTAMP"
+ }
+ },
+ "indexes": {},
+ "foreignKeys": {},
+ "compositePrimaryKeys": {},
+ "uniqueConstraints": {},
+ "checkConstraints": {}
+ },
+ "beta_runtime_settings": {
+ "name": "beta_runtime_settings",
+ "columns": {
+ "id": {
+ "name": "id",
+ "type": "text",
+ "primaryKey": true,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "signups_enabled": {
+ "name": "signups_enabled",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "updated_by_digest": {
+ "name": "updated_by_digest",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": false,
+ "autoincrement": false
+ },
+ "updated_at": {
+ "name": "updated_at",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": "CURRENT_TIMESTAMP"
+ }
+ },
+ "indexes": {},
+ "foreignKeys": {},
+ "compositePrimaryKeys": {},
+ "uniqueConstraints": {},
+ "checkConstraints": {}
+ },
+ "community_moderation_actions": {
+ "name": "community_moderation_actions",
+ "columns": {
+ "id": {
+ "name": "id",
+ "type": "text",
+ "primaryKey": true,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "story_id": {
+ "name": "story_id",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "actor_digest": {
+ "name": "actor_digest",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "action": {
+ "name": "action",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "from_status": {
+ "name": "from_status",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "to_status": {
+ "name": "to_status",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "note": {
+ "name": "note",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": "''"
+ },
+ "created_at": {
+ "name": "created_at",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": "CURRENT_TIMESTAMP"
+ }
+ },
+ "indexes": {
+ "community_moderation_story_idx": {
+ "name": "community_moderation_story_idx",
+ "columns": [
+ "story_id"
+ ],
+ "isUnique": false
+ },
+ "community_moderation_created_idx": {
+ "name": "community_moderation_created_idx",
+ "columns": [
+ "created_at"
+ ],
+ "isUnique": false
+ }
+ },
+ "foreignKeys": {
+ "community_moderation_actions_story_id_public_stories_id_fk": {
+ "name": "community_moderation_actions_story_id_public_stories_id_fk",
+ "tableFrom": "community_moderation_actions",
+ "tableTo": "public_stories",
+ "columnsFrom": [
+ "story_id"
+ ],
+ "columnsTo": [
+ "id"
+ ],
+ "onDelete": "cascade",
+ "onUpdate": "no action"
+ }
+ },
+ "compositePrimaryKeys": {},
+ "uniqueConstraints": {},
+ "checkConstraints": {}
+ },
+ "community_rate_limits": {
+ "name": "community_rate_limits",
+ "columns": {
+ "id": {
+ "name": "id",
+ "type": "text",
+ "primaryKey": true,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "vault_id": {
+ "name": "vault_id",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "action": {
+ "name": "action",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "window_key": {
+ "name": "window_key",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "count": {
+ "name": "count",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": 0
+ },
+ "updated_at": {
+ "name": "updated_at",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": "CURRENT_TIMESTAMP"
+ }
+ },
+ "indexes": {
+ "community_rate_vault_action_window_unique": {
+ "name": "community_rate_vault_action_window_unique",
+ "columns": [
+ "vault_id",
+ "action",
+ "window_key"
+ ],
+ "isUnique": true
+ },
+ "community_rate_window_idx": {
+ "name": "community_rate_window_idx",
+ "columns": [
+ "window_key"
+ ],
+ "isUnique": false
+ }
+ },
+ "foreignKeys": {
+ "community_rate_limits_vault_id_vaults_id_fk": {
+ "name": "community_rate_limits_vault_id_vaults_id_fk",
+ "tableFrom": "community_rate_limits",
+ "tableTo": "vaults",
+ "columnsFrom": [
+ "vault_id"
+ ],
+ "columnsTo": [
+ "id"
+ ],
+ "onDelete": "cascade",
+ "onUpdate": "no action"
+ }
+ },
+ "compositePrimaryKeys": {},
+ "uniqueConstraints": {},
+ "checkConstraints": {}
+ },
+ "debts": {
+ "name": "debts",
+ "columns": {
+ "id": {
+ "name": "id",
+ "type": "text",
+ "primaryKey": true,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "vault_id": {
+ "name": "vault_id",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "kind": {
+ "name": "kind",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "custom_label": {
+ "name": "custom_label",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": false,
+ "autoincrement": false
+ },
+ "currency": {
+ "name": "currency",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "original": {
+ "name": "original",
+ "type": "real",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "balance": {
+ "name": "balance",
+ "type": "real",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "monthly": {
+ "name": "monthly",
+ "type": "real",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "apr": {
+ "name": "apr",
+ "type": "real",
+ "primaryKey": false,
+ "notNull": false,
+ "autoincrement": false
+ },
+ "minimum_payment": {
+ "name": "minimum_payment",
+ "type": "real",
+ "primaryKey": false,
+ "notNull": false,
+ "autoincrement": false
+ },
+ "payment_status": {
+ "name": "payment_status",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": "'unknown'"
+ },
+ "remaining_months": {
+ "name": "remaining_months",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": false,
+ "autoincrement": false
+ },
+ "due_day": {
+ "name": "due_day",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "method": {
+ "name": "method",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "sharing_mode": {
+ "name": "sharing_mode",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": "'private'"
+ },
+ "last_paid_at": {
+ "name": "last_paid_at",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": false,
+ "autoincrement": false
+ },
+ "payments": {
+ "name": "payments",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": 0
+ },
+ "created_at": {
+ "name": "created_at",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": "CURRENT_TIMESTAMP"
+ },
+ "updated_at": {
+ "name": "updated_at",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": "CURRENT_TIMESTAMP"
+ }
+ },
+ "indexes": {
+ "debts_vault_id_idx": {
+ "name": "debts_vault_id_idx",
+ "columns": [
+ "vault_id"
+ ],
+ "isUnique": false
+ }
+ },
+ "foreignKeys": {
+ "debts_vault_id_vaults_id_fk": {
+ "name": "debts_vault_id_vaults_id_fk",
+ "tableFrom": "debts",
+ "tableTo": "vaults",
+ "columnsFrom": [
+ "vault_id"
+ ],
+ "columnsTo": [
+ "id"
+ ],
+ "onDelete": "cascade",
+ "onUpdate": "no action"
+ }
+ },
+ "compositePrimaryKeys": {},
+ "uniqueConstraints": {},
+ "checkConstraints": {}
+ },
+ "lucky_income_claims": {
+ "name": "lucky_income_claims",
+ "columns": {
+ "id": {
+ "name": "id",
+ "type": "text",
+ "primaryKey": true,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "vault_id": {
+ "name": "vault_id",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "event_date": {
+ "name": "event_date",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "created_at": {
+ "name": "created_at",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": "CURRENT_TIMESTAMP"
+ }
+ },
+ "indexes": {
+ "lucky_income_vault_day_unique": {
+ "name": "lucky_income_vault_day_unique",
+ "columns": [
+ "vault_id",
+ "event_date"
+ ],
+ "isUnique": true
+ }
+ },
+ "foreignKeys": {
+ "lucky_income_claims_vault_id_vaults_id_fk": {
+ "name": "lucky_income_claims_vault_id_vaults_id_fk",
+ "tableFrom": "lucky_income_claims",
+ "tableTo": "vaults",
+ "columnsFrom": [
+ "vault_id"
+ ],
+ "columnsTo": [
+ "id"
+ ],
+ "onDelete": "cascade",
+ "onUpdate": "no action"
+ }
+ },
+ "compositePrimaryKeys": {},
+ "uniqueConstraints": {},
+ "checkConstraints": {}
+ },
+ "owner_admins": {
+ "name": "owner_admins",
+ "columns": {
+ "id": {
+ "name": "id",
+ "type": "text",
+ "primaryKey": true,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "email_digest": {
+ "name": "email_digest",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "account_id": {
+ "name": "account_id",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": false,
+ "autoincrement": false
+ },
+ "role": {
+ "name": "role",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": "'owner'"
+ },
+ "activated_at": {
+ "name": "activated_at",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": "CURRENT_TIMESTAMP"
+ },
+ "last_seen_at": {
+ "name": "last_seen_at",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": "CURRENT_TIMESTAMP"
+ }
+ },
+ "indexes": {
+ "owner_admins_email_digest_unique": {
+ "name": "owner_admins_email_digest_unique",
+ "columns": [
+ "email_digest"
+ ],
+ "isUnique": true
+ },
+ "owner_admins_account_id_unique": {
+ "name": "owner_admins_account_id_unique",
+ "columns": [
+ "account_id"
+ ],
+ "isUnique": true
+ }
+ },
+ "foreignKeys": {
+ "owner_admins_account_id_accounts_id_fk": {
+ "name": "owner_admins_account_id_accounts_id_fk",
+ "tableFrom": "owner_admins",
+ "tableTo": "accounts",
+ "columnsFrom": [
+ "account_id"
+ ],
+ "columnsTo": [
+ "id"
+ ],
+ "onDelete": "set null",
+ "onUpdate": "no action"
+ }
+ },
+ "compositePrimaryKeys": {},
+ "uniqueConstraints": {},
+ "checkConstraints": {}
+ },
+ "payment_records": {
+ "name": "payment_records",
+ "columns": {
+ "id": {
+ "name": "id",
+ "type": "text",
+ "primaryKey": true,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "vault_id": {
+ "name": "vault_id",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "debt_id": {
+ "name": "debt_id",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "scheduled_date": {
+ "name": "scheduled_date",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": false,
+ "autoincrement": false
+ },
+ "confirmed_at": {
+ "name": "confirmed_at",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "event_date": {
+ "name": "event_date",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": false,
+ "autoincrement": false
+ },
+ "cash_payment": {
+ "name": "cash_payment",
+ "type": "real",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "new_balance": {
+ "name": "new_balance",
+ "type": "real",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "source": {
+ "name": "source",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": "'self_report'"
+ },
+ "income_type": {
+ "name": "income_type",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": false,
+ "autoincrement": false
+ },
+ "created_at": {
+ "name": "created_at",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": "CURRENT_TIMESTAMP"
+ }
+ },
+ "indexes": {
+ "payments_vault_id_idx": {
+ "name": "payments_vault_id_idx",
+ "columns": [
+ "vault_id"
+ ],
+ "isUnique": false
+ },
+ "payments_debt_id_idx": {
+ "name": "payments_debt_id_idx",
+ "columns": [
+ "debt_id"
+ ],
+ "isUnique": false
+ }
+ },
+ "foreignKeys": {
+ "payment_records_vault_id_vaults_id_fk": {
+ "name": "payment_records_vault_id_vaults_id_fk",
+ "tableFrom": "payment_records",
+ "tableTo": "vaults",
+ "columnsFrom": [
+ "vault_id"
+ ],
+ "columnsTo": [
+ "id"
+ ],
+ "onDelete": "cascade",
+ "onUpdate": "no action"
+ },
+ "payment_records_debt_id_debts_id_fk": {
+ "name": "payment_records_debt_id_debts_id_fk",
+ "tableFrom": "payment_records",
+ "tableTo": "debts",
+ "columnsFrom": [
+ "debt_id"
+ ],
+ "columnsTo": [
+ "id"
+ ],
+ "onDelete": "cascade",
+ "onUpdate": "no action"
+ }
+ },
+ "compositePrimaryKeys": {},
+ "uniqueConstraints": {},
+ "checkConstraints": {}
+ },
+ "policy_acceptances": {
+ "name": "policy_acceptances",
+ "columns": {
+ "id": {
+ "name": "id",
+ "type": "text",
+ "primaryKey": true,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "vault_id": {
+ "name": "vault_id",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "policy_key": {
+ "name": "policy_key",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "policy_version": {
+ "name": "policy_version",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "accepted_at": {
+ "name": "accepted_at",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": "CURRENT_TIMESTAMP"
+ }
+ },
+ "indexes": {
+ "policy_acceptance_vault_key_version_unique": {
+ "name": "policy_acceptance_vault_key_version_unique",
+ "columns": [
+ "vault_id",
+ "policy_key",
+ "policy_version"
+ ],
+ "isUnique": true
+ },
+ "policy_acceptance_vault_idx": {
+ "name": "policy_acceptance_vault_idx",
+ "columns": [
+ "vault_id"
+ ],
+ "isUnique": false
+ }
+ },
+ "foreignKeys": {
+ "policy_acceptances_vault_id_vaults_id_fk": {
+ "name": "policy_acceptances_vault_id_vaults_id_fk",
+ "tableFrom": "policy_acceptances",
+ "tableTo": "vaults",
+ "columnsFrom": [
+ "vault_id"
+ ],
+ "columnsTo": [
+ "id"
+ ],
+ "onDelete": "cascade",
+ "onUpdate": "no action"
+ }
+ },
+ "compositePrimaryKeys": {},
+ "uniqueConstraints": {},
+ "checkConstraints": {}
+ },
+ "public_stories": {
+ "name": "public_stories",
+ "columns": {
+ "id": {
+ "name": "id",
+ "type": "text",
+ "primaryKey": true,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "vault_id": {
+ "name": "vault_id",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "debt_id": {
+ "name": "debt_id",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "anonymous_name": {
+ "name": "anonymous_name",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "country_code": {
+ "name": "country_code",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": "''"
+ },
+ "debt_kind": {
+ "name": "debt_kind",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "amount_band": {
+ "name": "amount_band",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "currency": {
+ "name": "currency",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "repayment_approach": {
+ "name": "repayment_approach",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": "'other'"
+ },
+ "story_text": {
+ "name": "story_text",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "status": {
+ "name": "status",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": "'pending'"
+ },
+ "created_at": {
+ "name": "created_at",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": "CURRENT_TIMESTAMP"
+ },
+ "updated_at": {
+ "name": "updated_at",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": "CURRENT_TIMESTAMP"
+ }
+ },
+ "indexes": {
+ "public_stories_status_idx": {
+ "name": "public_stories_status_idx",
+ "columns": [
+ "status"
+ ],
+ "isUnique": false
+ },
+ "public_stories_vault_idx": {
+ "name": "public_stories_vault_idx",
+ "columns": [
+ "vault_id"
+ ],
+ "isUnique": false
+ }
+ },
+ "foreignKeys": {
+ "public_stories_vault_id_vaults_id_fk": {
+ "name": "public_stories_vault_id_vaults_id_fk",
+ "tableFrom": "public_stories",
+ "tableTo": "vaults",
+ "columnsFrom": [
+ "vault_id"
+ ],
+ "columnsTo": [
+ "id"
+ ],
+ "onDelete": "cascade",
+ "onUpdate": "no action"
+ },
+ "public_stories_debt_id_debts_id_fk": {
+ "name": "public_stories_debt_id_debts_id_fk",
+ "tableFrom": "public_stories",
+ "tableTo": "debts",
+ "columnsFrom": [
+ "debt_id"
+ ],
+ "columnsTo": [
+ "id"
+ ],
+ "onDelete": "cascade",
+ "onUpdate": "no action"
+ }
+ },
+ "compositePrimaryKeys": {},
+ "uniqueConstraints": {},
+ "checkConstraints": {}
+ },
+ "referral_codes": {
+ "name": "referral_codes",
+ "columns": {
+ "id": {
+ "name": "id",
+ "type": "text",
+ "primaryKey": true,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "vault_id": {
+ "name": "vault_id",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "code": {
+ "name": "code",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "status": {
+ "name": "status",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": "'active'"
+ },
+ "created_at": {
+ "name": "created_at",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": "CURRENT_TIMESTAMP"
+ }
+ },
+ "indexes": {
+ "referral_codes_vault_id_unique": {
+ "name": "referral_codes_vault_id_unique",
+ "columns": [
+ "vault_id"
+ ],
+ "isUnique": true
+ },
+ "referral_codes_code_unique": {
+ "name": "referral_codes_code_unique",
+ "columns": [
+ "code"
+ ],
+ "isUnique": true
+ },
+ "referral_codes_status_idx": {
+ "name": "referral_codes_status_idx",
+ "columns": [
+ "status"
+ ],
+ "isUnique": false
+ }
+ },
+ "foreignKeys": {
+ "referral_codes_vault_id_vaults_id_fk": {
+ "name": "referral_codes_vault_id_vaults_id_fk",
+ "tableFrom": "referral_codes",
+ "tableTo": "vaults",
+ "columnsFrom": [
+ "vault_id"
+ ],
+ "columnsTo": [
+ "id"
+ ],
+ "onDelete": "cascade",
+ "onUpdate": "no action"
+ }
+ },
+ "compositePrimaryKeys": {},
+ "uniqueConstraints": {},
+ "checkConstraints": {}
+ },
+ "referral_relationships": {
+ "name": "referral_relationships",
+ "columns": {
+ "id": {
+ "name": "id",
+ "type": "text",
+ "primaryKey": true,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "inviter_vault_id": {
+ "name": "inviter_vault_id",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "invited_vault_id": {
+ "name": "invited_vault_id",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "code_id": {
+ "name": "code_id",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "status": {
+ "name": "status",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": "'pending'"
+ },
+ "qualified_at": {
+ "name": "qualified_at",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": false,
+ "autoincrement": false
+ },
+ "rewarded_at": {
+ "name": "rewarded_at",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": false,
+ "autoincrement": false
+ },
+ "created_at": {
+ "name": "created_at",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": "CURRENT_TIMESTAMP"
+ }
+ },
+ "indexes": {
+ "referral_relationships_invited_vault_id_unique": {
+ "name": "referral_relationships_invited_vault_id_unique",
+ "columns": [
+ "invited_vault_id"
+ ],
+ "isUnique": true
+ },
+ "referrals_inviter_status_idx": {
+ "name": "referrals_inviter_status_idx",
+ "columns": [
+ "inviter_vault_id",
+ "status"
+ ],
+ "isUnique": false
+ },
+ "referrals_created_idx": {
+ "name": "referrals_created_idx",
+ "columns": [
+ "created_at"
+ ],
+ "isUnique": false
+ }
+ },
+ "foreignKeys": {
+ "referral_relationships_inviter_vault_id_vaults_id_fk": {
+ "name": "referral_relationships_inviter_vault_id_vaults_id_fk",
+ "tableFrom": "referral_relationships",
+ "tableTo": "vaults",
+ "columnsFrom": [
+ "inviter_vault_id"
+ ],
+ "columnsTo": [
+ "id"
+ ],
+ "onDelete": "cascade",
+ "onUpdate": "no action"
+ },
+ "referral_relationships_invited_vault_id_vaults_id_fk": {
+ "name": "referral_relationships_invited_vault_id_vaults_id_fk",
+ "tableFrom": "referral_relationships",
+ "tableTo": "vaults",
+ "columnsFrom": [
+ "invited_vault_id"
+ ],
+ "columnsTo": [
+ "id"
+ ],
+ "onDelete": "cascade",
+ "onUpdate": "no action"
+ },
+ "referral_relationships_code_id_referral_codes_id_fk": {
+ "name": "referral_relationships_code_id_referral_codes_id_fk",
+ "tableFrom": "referral_relationships",
+ "tableTo": "referral_codes",
+ "columnsFrom": [
+ "code_id"
+ ],
+ "columnsTo": [
+ "id"
+ ],
+ "onDelete": "cascade",
+ "onUpdate": "no action"
+ }
+ },
+ "compositePrimaryKeys": {},
+ "uniqueConstraints": {},
+ "checkConstraints": {}
+ },
+ "shore_value_ledger": {
+ "name": "shore_value_ledger",
+ "columns": {
+ "id": {
+ "name": "id",
+ "type": "text",
+ "primaryKey": true,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "vault_id": {
+ "name": "vault_id",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "event_key": {
+ "name": "event_key",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "event_type": {
+ "name": "event_type",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "points": {
+ "name": "points",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "reference_id": {
+ "name": "reference_id",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": false,
+ "autoincrement": false
+ },
+ "created_at": {
+ "name": "created_at",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": "CURRENT_TIMESTAMP"
+ }
+ },
+ "indexes": {
+ "shore_value_ledger_event_key_unique": {
+ "name": "shore_value_ledger_event_key_unique",
+ "columns": [
+ "event_key"
+ ],
+ "isUnique": true
+ },
+ "shore_value_vault_created_idx": {
+ "name": "shore_value_vault_created_idx",
+ "columns": [
+ "vault_id",
+ "created_at"
+ ],
+ "isUnique": false
+ },
+ "shore_value_event_type_idx": {
+ "name": "shore_value_event_type_idx",
+ "columns": [
+ "event_type"
+ ],
+ "isUnique": false
+ }
+ },
+ "foreignKeys": {
+ "shore_value_ledger_vault_id_vaults_id_fk": {
+ "name": "shore_value_ledger_vault_id_vaults_id_fk",
+ "tableFrom": "shore_value_ledger",
+ "tableTo": "vaults",
+ "columnsFrom": [
+ "vault_id"
+ ],
+ "columnsTo": [
+ "id"
+ ],
+ "onDelete": "cascade",
+ "onUpdate": "no action"
+ }
+ },
+ "compositePrimaryKeys": {},
+ "uniqueConstraints": {},
+ "checkConstraints": {}
+ },
+ "site_daily_visitors": {
+ "name": "site_daily_visitors",
+ "columns": {
+ "id": {
+ "name": "id",
+ "type": "text",
+ "primaryKey": true,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "visit_date": {
+ "name": "visit_date",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "visitor_digest": {
+ "name": "visitor_digest",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "first_source": {
+ "name": "first_source",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": "'direct'"
+ },
+ "first_locale": {
+ "name": "first_locale",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": "'zh'"
+ },
+ "first_path": {
+ "name": "first_path",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": "'/'"
+ },
+ "page_views": {
+ "name": "page_views",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": 1
+ },
+ "first_seen_at": {
+ "name": "first_seen_at",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": "CURRENT_TIMESTAMP"
+ },
+ "last_seen_at": {
+ "name": "last_seen_at",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": "CURRENT_TIMESTAMP"
+ }
+ },
+ "indexes": {
+ "site_daily_visitors_date_digest_unique": {
+ "name": "site_daily_visitors_date_digest_unique",
+ "columns": [
+ "visit_date",
+ "visitor_digest"
+ ],
+ "isUnique": true
+ },
+ "site_daily_visitors_date_idx": {
+ "name": "site_daily_visitors_date_idx",
+ "columns": [
+ "visit_date"
+ ],
+ "isUnique": false
+ },
+ "site_daily_visitors_source_date_idx": {
+ "name": "site_daily_visitors_source_date_idx",
+ "columns": [
+ "first_source",
+ "visit_date"
+ ],
+ "isUnique": false
+ }
+ },
+ "foreignKeys": {},
+ "compositePrimaryKeys": {},
+ "uniqueConstraints": {},
+ "checkConstraints": {}
+ },
+ "starlight_gifts": {
+ "name": "starlight_gifts",
+ "columns": {
+ "id": {
+ "name": "id",
+ "type": "text",
+ "primaryKey": true,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "sender_vault_id": {
+ "name": "sender_vault_id",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "recipient_vault_id": {
+ "name": "recipient_vault_id",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "story_id": {
+ "name": "story_id",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": false,
+ "autoincrement": false
+ },
+ "points": {
+ "name": "points",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "gift_date": {
+ "name": "gift_date",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "idempotency_key": {
+ "name": "idempotency_key",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "created_at": {
+ "name": "created_at",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": "CURRENT_TIMESTAMP"
+ }
+ },
+ "indexes": {
+ "starlight_gifts_idempotency_key_unique": {
+ "name": "starlight_gifts_idempotency_key_unique",
+ "columns": [
+ "idempotency_key"
+ ],
+ "isUnique": true
+ },
+ "starlight_sender_created_idx": {
+ "name": "starlight_sender_created_idx",
+ "columns": [
+ "sender_vault_id",
+ "created_at"
+ ],
+ "isUnique": false
+ },
+ "starlight_recipient_created_idx": {
+ "name": "starlight_recipient_created_idx",
+ "columns": [
+ "recipient_vault_id",
+ "created_at"
+ ],
+ "isUnique": false
+ }
+ },
+ "foreignKeys": {
+ "starlight_gifts_sender_vault_id_vaults_id_fk": {
+ "name": "starlight_gifts_sender_vault_id_vaults_id_fk",
+ "tableFrom": "starlight_gifts",
+ "tableTo": "vaults",
+ "columnsFrom": [
+ "sender_vault_id"
+ ],
+ "columnsTo": [
+ "id"
+ ],
+ "onDelete": "cascade",
+ "onUpdate": "no action"
+ },
+ "starlight_gifts_recipient_vault_id_vaults_id_fk": {
+ "name": "starlight_gifts_recipient_vault_id_vaults_id_fk",
+ "tableFrom": "starlight_gifts",
+ "tableTo": "vaults",
+ "columnsFrom": [
+ "recipient_vault_id"
+ ],
+ "columnsTo": [
+ "id"
+ ],
+ "onDelete": "cascade",
+ "onUpdate": "no action"
+ }
+ },
+ "compositePrimaryKeys": {},
+ "uniqueConstraints": {},
+ "checkConstraints": {}
+ },
+ "starlight_wallets": {
+ "name": "starlight_wallets",
+ "columns": {
+ "vault_id": {
+ "name": "vault_id",
+ "type": "text",
+ "primaryKey": true,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "available": {
+ "name": "available",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": 0
+ },
+ "lifetime_earned": {
+ "name": "lifetime_earned",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": 0
+ },
+ "lifetime_sent": {
+ "name": "lifetime_sent",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": 0
+ },
+ "lifetime_received": {
+ "name": "lifetime_received",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": 0
+ },
+ "updated_at": {
+ "name": "updated_at",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": "CURRENT_TIMESTAMP"
+ }
+ },
+ "indexes": {},
+ "foreignKeys": {
+ "starlight_wallets_vault_id_vaults_id_fk": {
+ "name": "starlight_wallets_vault_id_vaults_id_fk",
+ "tableFrom": "starlight_wallets",
+ "tableTo": "vaults",
+ "columnsFrom": [
+ "vault_id"
+ ],
+ "columnsTo": [
+ "id"
+ ],
+ "onDelete": "cascade",
+ "onUpdate": "no action"
+ }
+ },
+ "compositePrimaryKeys": {},
+ "uniqueConstraints": {},
+ "checkConstraints": {}
+ },
+ "story_encouragements": {
+ "name": "story_encouragements",
+ "columns": {
+ "id": {
+ "name": "id",
+ "type": "text",
+ "primaryKey": true,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "story_id": {
+ "name": "story_id",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "vault_id": {
+ "name": "vault_id",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "created_at": {
+ "name": "created_at",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": "CURRENT_TIMESTAMP"
+ }
+ },
+ "indexes": {
+ "story_encouragement_unique": {
+ "name": "story_encouragement_unique",
+ "columns": [
+ "story_id",
+ "vault_id"
+ ],
+ "isUnique": true
+ },
+ "story_encouragement_story_idx": {
+ "name": "story_encouragement_story_idx",
+ "columns": [
+ "story_id"
+ ],
+ "isUnique": false
+ }
+ },
+ "foreignKeys": {
+ "story_encouragements_story_id_public_stories_id_fk": {
+ "name": "story_encouragements_story_id_public_stories_id_fk",
+ "tableFrom": "story_encouragements",
+ "tableTo": "public_stories",
+ "columnsFrom": [
+ "story_id"
+ ],
+ "columnsTo": [
+ "id"
+ ],
+ "onDelete": "cascade",
+ "onUpdate": "no action"
+ },
+ "story_encouragements_vault_id_vaults_id_fk": {
+ "name": "story_encouragements_vault_id_vaults_id_fk",
+ "tableFrom": "story_encouragements",
+ "tableTo": "vaults",
+ "columnsFrom": [
+ "vault_id"
+ ],
+ "columnsTo": [
+ "id"
+ ],
+ "onDelete": "cascade",
+ "onUpdate": "no action"
+ }
+ },
+ "compositePrimaryKeys": {},
+ "uniqueConstraints": {},
+ "checkConstraints": {}
+ },
+ "story_reports": {
+ "name": "story_reports",
+ "columns": {
+ "id": {
+ "name": "id",
+ "type": "text",
+ "primaryKey": true,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "story_id": {
+ "name": "story_id",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "reporter_vault_id": {
+ "name": "reporter_vault_id",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "reason": {
+ "name": "reason",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "details": {
+ "name": "details",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": "''"
+ },
+ "status": {
+ "name": "status",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": "'open'"
+ },
+ "created_at": {
+ "name": "created_at",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": "CURRENT_TIMESTAMP"
+ },
+ "resolved_at": {
+ "name": "resolved_at",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": false,
+ "autoincrement": false
+ }
+ },
+ "indexes": {
+ "story_report_unique": {
+ "name": "story_report_unique",
+ "columns": [
+ "story_id",
+ "reporter_vault_id"
+ ],
+ "isUnique": true
+ },
+ "story_reports_status_idx": {
+ "name": "story_reports_status_idx",
+ "columns": [
+ "status"
+ ],
+ "isUnique": false
+ }
+ },
+ "foreignKeys": {
+ "story_reports_story_id_public_stories_id_fk": {
+ "name": "story_reports_story_id_public_stories_id_fk",
+ "tableFrom": "story_reports",
+ "tableTo": "public_stories",
+ "columnsFrom": [
+ "story_id"
+ ],
+ "columnsTo": [
+ "id"
+ ],
+ "onDelete": "cascade",
+ "onUpdate": "no action"
+ },
+ "story_reports_reporter_vault_id_vaults_id_fk": {
+ "name": "story_reports_reporter_vault_id_vaults_id_fk",
+ "tableFrom": "story_reports",
+ "tableTo": "vaults",
+ "columnsFrom": [
+ "reporter_vault_id"
+ ],
+ "columnsTo": [
+ "id"
+ ],
+ "onDelete": "cascade",
+ "onUpdate": "no action"
+ }
+ },
+ "compositePrimaryKeys": {},
+ "uniqueConstraints": {},
+ "checkConstraints": {}
+ },
+ "vaults": {
+ "name": "vaults",
+ "columns": {
+ "id": {
+ "name": "id",
+ "type": "text",
+ "primaryKey": true,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "recovery_hash": {
+ "name": "recovery_hash",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "alias": {
+ "name": "alias",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "region": {
+ "name": "region",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "pressure": {
+ "name": "pressure",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": "''"
+ },
+ "age_band": {
+ "name": "age_band",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": "''"
+ },
+ "gender": {
+ "name": "gender",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": "''"
+ },
+ "mbti": {
+ "name": "mbti",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": "''"
+ },
+ "zodiac": {
+ "name": "zodiac",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": "''"
+ },
+ "self_description": {
+ "name": "self_description",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": "''"
+ },
+ "repayment_plan": {
+ "name": "repayment_plan",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": "''"
+ },
+ "repayment_outlook": {
+ "name": "repayment_outlook",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": "''"
+ },
+ "income_plan": {
+ "name": "income_plan",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": "''"
+ },
+ "position_x": {
+ "name": "position_x",
+ "type": "real",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": 47
+ },
+ "position_y": {
+ "name": "position_y",
+ "type": "real",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": 63
+ },
+ "locale": {
+ "name": "locale",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": "'zh'"
+ },
+ "country_code": {
+ "name": "country_code",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": "''"
+ },
+ "country_name": {
+ "name": "country_name",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": "''"
+ },
+ "display_currency": {
+ "name": "display_currency",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": "'CNY'"
+ },
+ "monthly_income": {
+ "name": "monthly_income",
+ "type": "real",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": 0
+ },
+ "monthly_expenses": {
+ "name": "monthly_expenses",
+ "type": "real",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": 0
+ },
+ "discovery_consent": {
+ "name": "discovery_consent",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": false
+ },
+ "created_at": {
+ "name": "created_at",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": "CURRENT_TIMESTAMP"
+ },
+ "updated_at": {
+ "name": "updated_at",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": "CURRENT_TIMESTAMP"
+ }
+ },
+ "indexes": {
+ "vaults_recovery_hash_unique": {
+ "name": "vaults_recovery_hash_unique",
+ "columns": [
+ "recovery_hash"
+ ],
+ "isUnique": true
+ }
+ },
+ "foreignKeys": {},
+ "compositePrimaryKeys": {},
+ "uniqueConstraints": {},
+ "checkConstraints": {}
+ },
+ "world_category_candidates": {
+ "name": "world_category_candidates",
+ "columns": {
+ "id": {
+ "name": "id",
+ "type": "text",
+ "primaryKey": true,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "canonical_key": {
+ "name": "canonical_key",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "parent_kind": {
+ "name": "parent_kind",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": "'other'"
+ },
+ "name_zh": {
+ "name": "name_zh",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "name_en": {
+ "name": "name_en",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "description_zh": {
+ "name": "description_zh",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": "''"
+ },
+ "description_en": {
+ "name": "description_en",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": "''"
+ },
+ "status": {
+ "name": "status",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": "'candidate'"
+ },
+ "stage": {
+ "name": "stage",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": 0
+ },
+ "confidence": {
+ "name": "confidence",
+ "type": "real",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": 0
+ },
+ "unique_vaults": {
+ "name": "unique_vaults",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": 0
+ },
+ "region_count": {
+ "name": "region_count",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": 0
+ },
+ "mention_count": {
+ "name": "mention_count",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": 0
+ },
+ "emergence_score": {
+ "name": "emergence_score",
+ "type": "real",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": 0
+ },
+ "weight_profile_id": {
+ "name": "weight_profile_id",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": false,
+ "autoincrement": false
+ },
+ "merged_into_id": {
+ "name": "merged_into_id",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": false,
+ "autoincrement": false
+ },
+ "proposed_at": {
+ "name": "proposed_at",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": "CURRENT_TIMESTAMP"
+ },
+ "reviewed_at": {
+ "name": "reviewed_at",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": false,
+ "autoincrement": false
+ },
+ "published_at": {
+ "name": "published_at",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": false,
+ "autoincrement": false
+ },
+ "updated_at": {
+ "name": "updated_at",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": "CURRENT_TIMESTAMP"
+ }
+ },
+ "indexes": {
+ "world_category_candidates_canonical_key_unique": {
+ "name": "world_category_candidates_canonical_key_unique",
+ "columns": [
+ "canonical_key"
+ ],
+ "isUnique": true
+ },
+ "world_candidates_status_idx": {
+ "name": "world_candidates_status_idx",
+ "columns": [
+ "status"
+ ],
+ "isUnique": false
+ },
+ "world_candidates_score_idx": {
+ "name": "world_candidates_score_idx",
+ "columns": [
+ "emergence_score"
+ ],
+ "isUnique": false
+ }
+ },
+ "foreignKeys": {
+ "world_category_candidates_weight_profile_id_world_weight_profiles_id_fk": {
+ "name": "world_category_candidates_weight_profile_id_world_weight_profiles_id_fk",
+ "tableFrom": "world_category_candidates",
+ "tableTo": "world_weight_profiles",
+ "columnsFrom": [
+ "weight_profile_id"
+ ],
+ "columnsTo": [
+ "id"
+ ],
+ "onDelete": "no action",
+ "onUpdate": "no action"
+ }
+ },
+ "compositePrimaryKeys": {},
+ "uniqueConstraints": {},
+ "checkConstraints": {}
+ },
+ "world_growth_events": {
+ "name": "world_growth_events",
+ "columns": {
+ "id": {
+ "name": "id",
+ "type": "text",
+ "primaryKey": true,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "candidate_id": {
+ "name": "candidate_id",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "event_type": {
+ "name": "event_type",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "from_stage": {
+ "name": "from_stage",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": false,
+ "autoincrement": false
+ },
+ "to_stage": {
+ "name": "to_stage",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": false,
+ "autoincrement": false
+ },
+ "actor_type": {
+ "name": "actor_type",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": "'system'"
+ },
+ "weight_profile_id": {
+ "name": "weight_profile_id",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": false,
+ "autoincrement": false
+ },
+ "evidence_json": {
+ "name": "evidence_json",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": "'{}'"
+ },
+ "reason": {
+ "name": "reason",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": "''"
+ },
+ "created_at": {
+ "name": "created_at",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": "CURRENT_TIMESTAMP"
+ }
+ },
+ "indexes": {
+ "world_events_candidate_idx": {
+ "name": "world_events_candidate_idx",
+ "columns": [
+ "candidate_id"
+ ],
+ "isUnique": false
+ }
+ },
+ "foreignKeys": {
+ "world_growth_events_candidate_id_world_category_candidates_id_fk": {
+ "name": "world_growth_events_candidate_id_world_category_candidates_id_fk",
+ "tableFrom": "world_growth_events",
+ "tableTo": "world_category_candidates",
+ "columnsFrom": [
+ "candidate_id"
+ ],
+ "columnsTo": [
+ "id"
+ ],
+ "onDelete": "cascade",
+ "onUpdate": "no action"
+ },
+ "world_growth_events_weight_profile_id_world_weight_profiles_id_fk": {
+ "name": "world_growth_events_weight_profile_id_world_weight_profiles_id_fk",
+ "tableFrom": "world_growth_events",
+ "tableTo": "world_weight_profiles",
+ "columnsFrom": [
+ "weight_profile_id"
+ ],
+ "columnsTo": [
+ "id"
+ ],
+ "onDelete": "no action",
+ "onUpdate": "no action"
+ }
+ },
+ "compositePrimaryKeys": {},
+ "uniqueConstraints": {},
+ "checkConstraints": {}
+ },
+ "world_signal_assignments": {
+ "name": "world_signal_assignments",
+ "columns": {
+ "id": {
+ "name": "id",
+ "type": "text",
+ "primaryKey": true,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "vault_id": {
+ "name": "vault_id",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "debt_id": {
+ "name": "debt_id",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "candidate_id": {
+ "name": "candidate_id",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "confidence": {
+ "name": "confidence",
+ "type": "real",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "assignment_source": {
+ "name": "assignment_source",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": "'ai'"
+ },
+ "taxonomy_version": {
+ "name": "taxonomy_version",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": 1
+ },
+ "created_at": {
+ "name": "created_at",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": "CURRENT_TIMESTAMP"
+ },
+ "updated_at": {
+ "name": "updated_at",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": "CURRENT_TIMESTAMP"
+ }
+ },
+ "indexes": {
+ "world_signal_assignments_debt_id_unique": {
+ "name": "world_signal_assignments_debt_id_unique",
+ "columns": [
+ "debt_id"
+ ],
+ "isUnique": true
+ },
+ "world_signals_vault_idx": {
+ "name": "world_signals_vault_idx",
+ "columns": [
+ "vault_id"
+ ],
+ "isUnique": false
+ },
+ "world_signals_candidate_idx": {
+ "name": "world_signals_candidate_idx",
+ "columns": [
+ "candidate_id"
+ ],
+ "isUnique": false
+ }
+ },
+ "foreignKeys": {
+ "world_signal_assignments_vault_id_vaults_id_fk": {
+ "name": "world_signal_assignments_vault_id_vaults_id_fk",
+ "tableFrom": "world_signal_assignments",
+ "tableTo": "vaults",
+ "columnsFrom": [
+ "vault_id"
+ ],
+ "columnsTo": [
+ "id"
+ ],
+ "onDelete": "cascade",
+ "onUpdate": "no action"
+ },
+ "world_signal_assignments_debt_id_debts_id_fk": {
+ "name": "world_signal_assignments_debt_id_debts_id_fk",
+ "tableFrom": "world_signal_assignments",
+ "tableTo": "debts",
+ "columnsFrom": [
+ "debt_id"
+ ],
+ "columnsTo": [
+ "id"
+ ],
+ "onDelete": "cascade",
+ "onUpdate": "no action"
+ },
+ "world_signal_assignments_candidate_id_world_category_candidates_id_fk": {
+ "name": "world_signal_assignments_candidate_id_world_category_candidates_id_fk",
+ "tableFrom": "world_signal_assignments",
+ "tableTo": "world_category_candidates",
+ "columnsFrom": [
+ "candidate_id"
+ ],
+ "columnsTo": [
+ "id"
+ ],
+ "onDelete": "cascade",
+ "onUpdate": "no action"
+ }
+ },
+ "compositePrimaryKeys": {},
+ "uniqueConstraints": {},
+ "checkConstraints": {}
+ },
+ "world_weight_profiles": {
+ "name": "world_weight_profiles",
+ "columns": {
+ "id": {
+ "name": "id",
+ "type": "text",
+ "primaryKey": true,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "version": {
+ "name": "version",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "status": {
+ "name": "status",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": "'draft'"
+ },
+ "frequency_weight": {
+ "name": "frequency_weight",
+ "type": "real",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "growth_weight": {
+ "name": "growth_weight",
+ "type": "real",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "geography_weight": {
+ "name": "geography_weight",
+ "type": "real",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "recurrence_weight": {
+ "name": "recurrence_weight",
+ "type": "real",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "connection_weight": {
+ "name": "connection_weight",
+ "type": "real",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "quality_weight": {
+ "name": "quality_weight",
+ "type": "real",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "proposed_by": {
+ "name": "proposed_by",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": "'human'"
+ },
+ "model_ref": {
+ "name": "model_ref",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": false,
+ "autoincrement": false
+ },
+ "rationale": {
+ "name": "rationale",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": "''"
+ },
+ "created_at": {
+ "name": "created_at",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": "CURRENT_TIMESTAMP"
+ },
+ "activated_at": {
+ "name": "activated_at",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": false,
+ "autoincrement": false
+ }
+ },
+ "indexes": {
+ "world_weight_profiles_version_unique": {
+ "name": "world_weight_profiles_version_unique",
+ "columns": [
+ "version"
+ ],
+ "isUnique": true
+ }
+ },
+ "foreignKeys": {},
+ "compositePrimaryKeys": {},
+ "uniqueConstraints": {},
+ "checkConstraints": {}
+ }
+ },
+ "views": {},
+ "enums": {},
+ "_meta": {
+ "schemas": {},
+ "tables": {},
+ "columns": {}
+ },
+ "internal": {
+ "indexes": {}
+ }
+}
\ No newline at end of file
diff --git a/drizzle/meta/_journal.json b/drizzle/meta/_journal.json
new file mode 100644
index 0000000..1894720
--- /dev/null
+++ b/drizzle/meta/_journal.json
@@ -0,0 +1,132 @@
+{
+ "version": "7",
+ "dialect": "sqlite",
+ "entries": [
+ {
+ "idx": 0,
+ "version": "6",
+ "when": 1785315776503,
+ "tag": "0000_oval_jocasta",
+ "breakpoints": true
+ },
+ {
+ "idx": 1,
+ "version": "6",
+ "when": 1785318657041,
+ "tag": "0001_sad_wendell_vaughn",
+ "breakpoints": true
+ },
+ {
+ "idx": 2,
+ "version": "6",
+ "when": 1785320413708,
+ "tag": "0002_pink_next_avengers",
+ "breakpoints": true
+ },
+ {
+ "idx": 3,
+ "version": "6",
+ "when": 1785337218287,
+ "tag": "0003_tough_black_bird",
+ "breakpoints": true
+ },
+ {
+ "idx": 4,
+ "version": "6",
+ "when": 1785384626007,
+ "tag": "0004_skinny_xavin",
+ "breakpoints": true
+ },
+ {
+ "idx": 5,
+ "version": "6",
+ "when": 1785385758817,
+ "tag": "0005_curious_ultragirl",
+ "breakpoints": true
+ },
+ {
+ "idx": 6,
+ "version": "6",
+ "when": 1785385911555,
+ "tag": "0006_supreme_james_howlett",
+ "breakpoints": true
+ },
+ {
+ "idx": 7,
+ "version": "6",
+ "when": 1785389428084,
+ "tag": "0007_faulty_nova",
+ "breakpoints": true
+ },
+ {
+ "idx": 8,
+ "version": "6",
+ "when": 1785390878476,
+ "tag": "0008_shiny_squirrel_girl",
+ "breakpoints": true
+ },
+ {
+ "idx": 9,
+ "version": "6",
+ "when": 1785394249229,
+ "tag": "0009_numerous_marvex",
+ "breakpoints": true
+ },
+ {
+ "idx": 10,
+ "version": "6",
+ "when": 1785399769830,
+ "tag": "0010_opposite_solo",
+ "breakpoints": true
+ },
+ {
+ "idx": 11,
+ "version": "6",
+ "when": 1785401150744,
+ "tag": "0011_bent_black_knight",
+ "breakpoints": true
+ },
+ {
+ "idx": 12,
+ "version": "6",
+ "when": 1785416445442,
+ "tag": "0012_overrated_alex_power",
+ "breakpoints": true
+ },
+ {
+ "idx": 13,
+ "version": "6",
+ "when": 1785419916223,
+ "tag": "0013_faithful_silverclaw",
+ "breakpoints": true
+ },
+ {
+ "idx": 14,
+ "version": "6",
+ "when": 1785477976901,
+ "tag": "0014_sad_pestilence",
+ "breakpoints": true
+ },
+ {
+ "idx": 15,
+ "version": "6",
+ "when": 1785506881576,
+ "tag": "0015_steep_praxagora",
+ "breakpoints": true
+ },
+ {
+ "idx": 16,
+ "version": "6",
+ "when": 1785558938933,
+ "tag": "0016_icy_magdalene",
+ "breakpoints": true
+ },
+ {
+ "idx": 17,
+ "version": "6",
+ "when": 1785571120558,
+ "tag": "0017_last_hellcat",
+ "breakpoints": true
+ }
+ ]
+}
\ No newline at end of file
diff --git a/eslint.config.mjs b/eslint.config.mjs
new file mode 100644
index 0000000..05e726d
--- /dev/null
+++ b/eslint.config.mjs
@@ -0,0 +1,18 @@
+import { defineConfig, globalIgnores } from "eslint/config";
+import nextVitals from "eslint-config-next/core-web-vitals";
+import nextTs from "eslint-config-next/typescript";
+
+const eslintConfig = defineConfig([
+ ...nextVitals,
+ ...nextTs,
+ // Override default ignores of eslint-config-next.
+ globalIgnores([
+ // Default ignores of eslint-config-next:
+ ".next/**",
+ "out/**",
+ "build/**",
+ "next-env.d.ts",
+ ]),
+]);
+
+export default eslintConfig;
diff --git a/examples/d1/app/api/notes/route.ts b/examples/d1/app/api/notes/route.ts
new file mode 100644
index 0000000..07f8318
--- /dev/null
+++ b/examples/d1/app/api/notes/route.ts
@@ -0,0 +1,58 @@
+import { desc } from "drizzle-orm";
+import { getDb } from "../../../../../db";
+import { notes } from "../../../db/schema";
+
+function toRouteErrorMessage(error: unknown) {
+ const message = error instanceof Error ? error.message : "Unexpected error";
+ const detail =
+ error instanceof Error && error.cause instanceof Error ? error.cause.message : "";
+ const combined = `${message}\n${detail}`;
+
+ if (combined.includes("no such table") || combined.includes('from "notes"')) {
+ return "The notes table is unavailable. Generate the migration locally with `npm run db:generate`, then deploy so the platform can apply the generated SQL to the real D1 database.";
+ }
+
+ return message;
+}
+
+export async function GET() {
+ try {
+ const db = getDb();
+ const rows = await db
+ .select()
+ .from(notes)
+ .orderBy(desc(notes.createdAt), desc(notes.id))
+ .limit(20);
+
+ return Response.json({ notes: rows });
+ } catch (error) {
+ return Response.json(
+ { error: toRouteErrorMessage(error) },
+ { status: 500 }
+ );
+ }
+}
+
+export async function POST(request: Request) {
+ try {
+ const payload = (await request.json()) as {
+ title?: string;
+ content?: string;
+ };
+ const title = payload.title?.trim() ?? "";
+ const content = payload.content?.trim() ?? "";
+
+ if (!title) {
+ return Response.json({ error: "title is required" }, { status: 400 });
+ }
+
+ const db = getDb();
+ const [note] = await db.insert(notes).values({ title, content }).returning();
+ return Response.json({ note }, { status: 201 });
+ } catch (error) {
+ return Response.json(
+ { error: toRouteErrorMessage(error) },
+ { status: 500 }
+ );
+ }
+}
diff --git a/examples/d1/db/schema.ts b/examples/d1/db/schema.ts
new file mode 100644
index 0000000..7bb0c15
--- /dev/null
+++ b/examples/d1/db/schema.ts
@@ -0,0 +1,9 @@
+import { sql } from "drizzle-orm";
+import { integer, sqliteTable, text } from "drizzle-orm/sqlite-core";
+
+export const notes = sqliteTable("notes", {
+ id: integer("id").primaryKey({ autoIncrement: true }),
+ title: text("title").notNull(),
+ content: text("content").notNull().default(""),
+ createdAt: text("created_at").notNull().default(sql`CURRENT_TIMESTAMP`),
+});
diff --git a/launch-kit/CHANNEL_PLAYBOOK.md b/launch-kit/CHANNEL_PLAYBOOK.md
new file mode 100644
index 0000000..a416fd4
--- /dev/null
+++ b/launch-kit/CHANNEL_PLAYBOOK.md
@@ -0,0 +1,160 @@
+# 上岸星球分阶段全球传播方案
+
+目标不是“一夜爆量”,而是用安全、可控的批次让真实用户推动世界成长。
+
+## 阶段 0:今晚完成发布准备
+
+目标:所有渠道使用同一套名字、事实和隐私承诺。
+
+- 固定中文名“上岸星球”、英文名“Debt World”。
+- 准备宽屏、方形、竖版视觉和中英文文案。
+- 完成公测开关、人数上限、暂停注册和异常处理清单。
+- Product Hunt 先创建个人账号和草稿,不立刻发布。
+- GitHub 继续私有,先准备公开说明;未确定许可证前不公开源码。
+
+## 阶段 1:30–100 名种子用户(7 天)
+
+目标:证明陌生用户能完成首次债务整理,并愿意回来一次。
+
+人群结构:
+
+- 40% 中文用户、40% 英文用户、20% 双语或其他母语用户。
+- 覆盖房贷、信用卡、学贷、经营、医疗、亲友借款和自定义类型。
+- 至少一半手机用户;至少 10 位慢网或旧设备用户。
+
+渠道:
+
+- 内测用户每人最多推荐 1 人。
+- 创始人的真实创作记录,而不是广告式群发。
+- 得到管理员许可的小型财务、独立开发或互助社区。
+- LinkedIn、Bluesky、Threads 发布创始人故事。
+
+进入下一阶段门槛:
+
+- 首笔债务完成率 ≥ 60%。
+- 7 日回访率 ≥ 25%。
+- 数据删除成功率 = 100%。
+- 跨账户、安全、密码泄露和危险建议事件 = 0。
+- 普通举报 72 小时内处理,安全举报 24 小时内处理。
+
+## 阶段 2:100–500 名公开测试用户(14 天)
+
+目标:验证世界地图、社区审核和不同国家的货币理解。
+
+渠道顺序:
+
+1. 官网开放有限注册,每日设置名额。
+2. Product Hunt 草稿准备完成后择日发布;只邀请人们访问和评论,不要求点赞。
+3. Show HN 只在无需邀请码即可实际体验时发布。
+4. Reddit 必须先看社区规则或联系版主;每个社区单独写,不批量复制。
+5. GitHub 发布产品说明、路线图和非代码贡献入口;源码是否公开另行决定。
+
+内容节奏:
+
+- 周一:为什么做——反“人均富豪”错觉。
+- 周三:一分钟功能演示——对话、角色、锁链、还款。
+- 周五:隐私怎么做——默认私密、审核、删除。
+- 周日:本周改了什么——只报告真实反馈和修复。
+
+进入下一阶段门槛:
+
+- 至少 3 个国家各有 20 名有效用户。
+- 至少 50 名用户完成第二次余额/还款/收入更新。
+- 社区待审核积压不超过 24 小时正常处理能力。
+- AI、数据库和带宽成本在设定日预算内。
+
+## 阶段 3:500–2,000 名国际用户(30 天)
+
+目标:验证跨文化表达、世界数据和志愿翻译机制。
+
+- 从英语、西班牙语、葡萄牙语、日语四个候选方向中,按真实访问和志愿者数量选择两种,不同时开四种。
+- 招募“语言守护者”,只校对界面、隐私和危机提示,不让志愿者接触个人债务数据。
+- 在每个语言社区使用当地真实案例表达,不直接机器翻译中文帖子。
+- 邀请财务教育、消费者权益和心理健康领域的专业人士审阅边界,但不把他们包装成产品背书。
+- 开始发布匿名聚合洞察,所有群体必须达到隐私门槛,不做个人羞辱榜。
+
+## 阶段 4:2,000–10,000 名世界建设者
+
+目标:让数据开始安全地长出新建筑、债务社区和方法库。
+
+- 新债务方向必须达到人数、地区和时间门槛,经管理员审核后才成为建筑。
+- 建立公开路线图和月度“世界长大了什么”更新。
+- 发布经验证的上岸故事列表,不接受一天内创建的小额债务刷榜。
+- 用户达到 10,000 且 30 日留存、审核能力和成本稳定后,启动小程序,不仅看注册总数。
+
+## 零预算渠道优先级
+
+| 优先级 | 渠道 | 目的 | 做法 |
+|---:|---|---|---|
+| 1 | 现有用户转介绍 | 找到真实债务需求 | 每人最多邀请 1 人 |
+| 2 | 创始人个人内容 | 建立信任 | 讲为什么做和本周修复 |
+| 3 | GitHub | 找开发、翻译、隐私贡献者 | 清晰 README、反馈模板、路线图 |
+| 4 | Product Hunt | 全球早期采用者 | 产品可直接体验后集中发布 |
+| 5 | Show HN | 技术与产品批评 | 降低注册门槛,创始人全程回复 |
+| 6 | Reddit | 找垂直真实用户 | 先看规则/问版主,不群发私信 |
+| 7 | LinkedIn/Bluesky/Threads | 扩散创始人故事 | 个人账号,不伪装机构 |
+| 8 | 小红书/视频号 | 中文创作过程 | 不绕规则做外链或私域引流 |
+
+## 30 天内容日历
+
+### 第 1 周:问题与初心
+
+- Day 1:为什么“人均富豪”错觉会伤害普通人。
+- Day 3:30 秒展示匿名角色如何生成。
+- Day 5:为什么不做“谁欠最多”的排行榜。
+- Day 7:一周真实修改清单。
+
+### 第 2 周:功能与信任
+
+- Day 9:一笔房贷如何变成余额、利率、月供和进度。
+- Day 11:提前还款为什么不能把整笔现金都算成本金。
+- Day 13:数据在哪里、如何导出和删除。
+- Day 14:邀请第一批陌生测试者。
+
+### 第 3 周:真实世界
+
+- Day 16:不同国家金额如何换算且保留原币。
+- Day 18:匿名故事怎样审核、清理精确数字。
+- Day 20:送一点光为什么只做固定鼓励。
+- Day 21:公布匿名使用漏斗,不公布总债务金额。
+
+### 第 4 周:共同建设
+
+- Day 23:新增债务类型怎样长成未来建筑。
+- Day 25:公开本月最难修的问题。
+- Day 27:邀请翻译、无障碍和隐私贡献者。
+- Day 30:月度世界更新和下一阶段门槛。
+
+## 每个平台都要遵守
+
+- 不购买假用户、评论或点赞。
+- 不自动私信、不批量复制同一帖子、不用多个账号顶帖。
+- 不让用户在评论区公开精确债务、密码或身份信息。
+- 不用“焦虑测试”“你多久上岸”等恐惧型标题诱导填写数据。
+- Product Hunt 不直接要求 upvote;Show HN 不请朋友投票;Reddit 先遵守具体社区规则。
+- 所有用户案例必须有授权,金额默认改为区间,且不夸大结果。
+
+## 每日增长看板
+
+- 访问人数。
+- 注册开始率、注册完成率。
+- 首笔债务完成率。
+- 角色创建完成率。
+- 反馈提交率。
+- 第 1/7/30 日回访率。
+- 第二次真实数据更新人数。
+- 故事投稿、批准、拒绝、举报和处理时间。
+- 导出与删除成功率。
+- AI 请求量、失败率和成本。
+- 严重安全事件数。
+
+“累计总债务”“欠最多的人”和 AI 对话原文永远不作为增长战报。
+
+## 参考结构
+
+- Actual Budget:先讲免费、本地优先与社区贡献。
+- Firefly III:先讲个人动机和财务安全感,再解释功能。
+- Organic Maps:用清楚的“不追踪、不广告”等边界建立信任。
+- Product Hunt 官方发布指南:
+- Show HN 官方规则:
+- Reddit 官方反垃圾规则:
diff --git a/launch-kit/DAILY_GROWTH_OPERATIONS.md b/launch-kit/DAILY_GROWTH_OPERATIONS.md
new file mode 100644
index 0000000..db4f0e7
--- /dev/null
+++ b/launch-kit/DAILY_GROWTH_OPERATIONS.md
@@ -0,0 +1,389 @@
+# Debt World / 上岸星球:每日真实增长运营台账
+
+更新时间:2026-08-03
+官网:
+英文公测入口:
+
+## 增长原则
+
+- 目标是真实完成体验的用户,而不是空注册、买量、机器人或互刷。
+- 核心漏斗:独立访客 → 注册 → 创建角色 → 添加首笔债务 → 7 日回访。
+- 每个外部渠道使用独立来源参数:`src=github`、`src=reddit`、`src=x`。
+- 不批量发帖、评论、私信、点赞、关注或跨社区复制刷屏。
+- 不在个人债务求助帖下面植入产品链接,不要求用户公开精确债务。
+- 所有对外内容明确披露创始人/开发者身份,并邀请真实、尖锐的反馈。
+
+## 2026-08-01 基线
+
+后台验证时的聚合数据:
+
+- 独立访客:2(包含发布验证访问)
+- 页面打开:2(包含发布验证访问)
+- 注册账户:1
+- 大世界角色:3
+- 已记录债务:3
+- 待处理反馈:2
+- 有效邀请:0
+
+这些数字仅作首日基线。不得把角色数误写成真实注册用户数。
+
+## 2026-08-01 执行状态
+
+- Reddit:已发布到 `r/alphaandbetausers`,标题包含社区要求的 `[Web, Beta]` 标签,公开页面已核验可访问: 。后续只在原帖回复真实评论,不向其他社区复制轰炸。
+- GitHub:Issue #1 已通过登录网页完成更新,并再次读取公开页面核验。标题和双语正文均为当前公测流程,旧的“匿名保险箱 / 恢复码”说明已全部移除:。
+
+### 17:25 公测检查点
+
+- 今日独立访客:4
+- 今日页面打开:4
+- 今日新增注册:0
+- 今日首次录债:0
+- Reddit 来源转化:暂未出现
+- Reddit 真实评论:暂未出现
+
+当前数据说明发布链接已经被打开,但尚未形成新用户。继续等待自然测试者,不用重复发帖或制造虚假访问。
+
+## 今日 GitHub 动作
+
+目标:仅更新自有仓库 `rback37/debt-world` 的 Public Beta Issue #1。
+地址:
+
+### 新标题
+
+`[Public Beta] Test Debt World: clarity, privacy, and real return value`
+
+### 新正文
+
+I am building **Debt World / 上岸星球**, a free bilingual public beta that turns a private debt journey into a walkable, game-like world—without pretending the debt is only a game.
+
+**Try the beta**
+
+- English:
+- 中文:
+- Product and privacy overview:
+
+### What a tester can do
+
+1. Create an anonymous username-and-password account; no email or legal name is required.
+2. Choose a country and local currency.
+3. Talk with Kian to organize pressure, income, living costs, interest, due dates, and possible next steps.
+4. Add multiple debts and update progress from real repayments, prepayments, or extra income.
+5. Enter one shared world where limited anonymous patterns help the world grow. Exact personal amounts remain private.
+6. Invite someone with a personal link. Rewards activate only after that person adds a first debt, so empty signups do not count.
+
+### The five questions I most need answered
+
+- Which onboarding step is confusing?
+- What privacy wording is unclear or unconvincing?
+- Which debt type or repayment situation is missing?
+- What would make you return in seven days?
+- Did the experience reduce pressure, increase it, or have no effect?
+
+Please do **not** post passwords, bank details, identity documents, exact private debt figures, or private AI conversations in this issue. Use the in-product **Feedback** entry for a bug report or privacy concern.
+
+Debt World does not connect to banks, sell loans or debt relief, or replace financial/legal advice. Honest and blunt feedback is more useful than a positive review.
+
+---
+
+我正在开发免费的中英双语公测产品 **Debt World / 上岸星球**:把匿名、真实的债务整理与还款进度放进一个可以行走、会随数据成长的世界中,同时避免把负债痛苦娱乐化。
+
+**参与公测**
+
+- 中文:
+- English:
+- 产品与隐私说明:
+
+测试者可以使用匿名账号,选择国家和本地货币,与小岸梳理压力、收入、日常开销、利息和还款日,分别添加多项债务,并用真实还款、提前还款或幸运收入更新进度。所有人进入同一个共享世界,但个人精确金额默认不公开。
+
+我最需要知道:哪一步看不懂、哪句隐私说明不可信、缺了什么债务类型、什么会让你 7 天后回来,以及体验是否真的缓解了一点压力。
+
+请不要在 Issue 中公开密码、银行卡、身份证件、精确私人债务或私人 AI 对话。漏洞和隐私问题请使用站内“反馈”入口。产品不连接银行、不销售贷款或债务服务,也不代替财务或法律专业意见。
+
+## 今日 Reddit 候选动作
+
+目标社区:`r/alphaandbetausers`
+理由:社区定位就是为 App/网站寻找 Alpha/Beta 测试者,当前页面可创建测试招募帖。
+ tracked link:
+
+### 标题
+
+`Looking for 20 honest testers for a walkable, anonymous debt world`
+
+### 正文
+
+I’m the founder and builder of **Debt World**, a free bilingual public beta created to counter a feeling that social feeds can amplify: everyone else seems rich, while ordinary debt and repayment pressure stay invisible.
+
+The product turns a self-reported debt journey into a walkable, game-like world. A tester can create an anonymous username, choose a country and local currency, talk with Kian to organize the situation, add multiple debt types, and update progress from real repayments, prepayments, or extra income. Characters and the shared world change with those updates.
+
+It does not connect to a bank, sell loans or debt relief, or replace professional financial or legal advice. Exact personal amounts remain private on the public map.
+
+I’m looking for up to 20 people who can spend about 10 minutes testing the onboarding. Please do not enter anything you are uncomfortable storing, and do not share exact debt figures in the comments.
+
+The feedback I need most:
+
+1. Which step was confusing?
+2. What privacy concern would stop you from continuing?
+3. Which debt type or repayment situation is missing?
+4. Would you return in seven days to update progress? Why or why not?
+
+Public beta:
+
+Disclosure: I built it. The beta is free. Blunt feedback is much more useful than a positive review.
+
+## 发布后 48 小时动作
+
+- 0–2 小时:创始人本人回复每一条真实评论,不复制模板刷屏。
+- 6 小时:记录 Reddit/GitHub 来源的访问、注册、首笔债务和报错。
+- 24 小时:在原帖透明补充学到了什么、修了什么;不去第二个社区重复发帖。
+- 48 小时:根据完成率和反馈质量决定是否寻找第二个测试社区。
+- 7 天:查看回访,不把一次性注册误当作留存用户。
+
+## 每日记录格式
+
+| 日期 | 渠道 | 动作 | 独立访客 | 注册 | 首笔债务 | 有效邀请 | 反馈 | 7 日回访 | 结论 |
+|---|---|---|---:|---:|---:|---:|---:|---:|---|
+| 2026-08-01 | 基线 | SEO、邀请闭环、后台统计上线 | 2 | 1 | 待分渠道 | 0 | 2 | 尚未形成 | 启动公测 |
+| 2026-08-01 17:25 | Reddit + GitHub | Reddit 首帖公开;GitHub Issue 完成修复 | 4 | 0(今日) | 0(今日) | 0 | 0(今日) | 尚未形成 | 有访问,等待首个渠道转化 |
+
+## 下一候选渠道
+
+- X:账号资料完成后,每天一条有独立价值的英文优先内容;不自动点赞、关注、回复或私信。
+- Reddit 第二站:只在首帖互动处理完成后筛选,发布当天重新核对社区规则。
+- 债务互助社区:先联系版主获得许可;未获许可不贴产品链接。
+- GitHub:继续使用 Issues 收集可复现问题和产品反馈,不去无关项目下推广。
+
+## 2026-08-01 每日宣传素材
+
+- 功能主题:可行走的匿名共同债务世界;不同国家的人背负不同债务,但不必独自承受。
+- 新图片:`launch-kit/daily-social/2026-08-01-shared-world.png`
+- 邀请入口:
+- 图片隐私检查:无真实金额、无个人债务资料、无虚构用户统计、无“保证上岸”承诺。
+- 当日渠道原则:Reddit 已有公测首帖,不重复发;优先使用 X 发布一次带图原创内容。
+
+### X 发布文案
+
+I built Debt World because social feeds can make it feel like everyone else is rich. It is a walkable anonymous world for mapping debts, cash flow, and real repayment progress across countries. Join my beta world: https://www.debtworld.org/?ref=SHORE-39BSQL8T&src=friend
+
+### 当日发送结果
+
+- X:发布页连续连接超时,未声称发布成功。
+- Reddit 个人主页:带图帖子已准备;平台在提交前要求真人验证码,因此交由创始人本人完成验证和最终提交。
+- 本轮不向第二个 Reddit 社区复制公测帖,避免同日重复推广。
+
+## 2026-08-02 每日宣传素材
+
+- 功能主题:把“我一共欠多少”拆成房贷、信用卡、学贷、亲友借款等不同来源,并把收入、生活开销和还款放进同一张清晰地图。
+- 新图片:`launch-kit/daily-social/2026-08-02-multi-debt-cashflow.png`
+- 邀请入口:
+- 图片隐私检查:无真实金额、无个人资料、无虚构用户统计、无保证结果或诱导借贷表述。
+- 网站状态:Sites 项目为 `active`,正式版本 43,访问权限为 `public`,独立域名仍指向正式站点。本机命令行与内置浏览器受 Cloudflare 拦截或连接重置,暂不能把该现象当作全球宕机;发布前继续用真实海外浏览器验证落地页。
+
+### X / Threads 短文案(241 字符)
+
+One debt total can hide the real problem. Debt World maps mortgages, cards, student loans and money owed to friends beside income, living costs and repayments. I built it—try the beta: https://www.debtworld.org/?ref=SHORE-39BSQL8T&src=friend
+
+### Reddit 个人主页 / Build in public 文案
+
+**Multiple debts. One clear map.**
+
+A single total can hide what is actually causing the pressure. In Debt World, people can separate a mortgage, credit card, student loan, medical bill, business debt, or money owed to friends; then place those balances beside income, living costs, interest, due dates, and real repayment updates.
+
+The goal is not to turn debt into a competition. It is to make the situation easier to understand, show that ordinary people are not alone, and help each person find a realistic next step.
+
+I built the public beta and would value blunt feedback on the first ten minutes—especially what feels confusing, intrusive, or missing.
+
+Try it:
+
+The beta is free. It does not connect to banks, sell loans or debt relief, or replace financial or legal advice. Please do not post private debt figures in public comments.
+
+### 今日渠道判断
+
+- GitHub:公开仓库 README 已存在完整双语项目介绍、隐私边界、协作和融资诉求及正式公测入口;2026-08-02 重新读取公开仓库确认内容存在,不再为了“看起来更新”重复修改。
+- Reddit:首个公测帖已发布;下一条只放创始人个人主页或规则允许的 build-in-public 社区,使用新的功能角度,不复制首帖。
+- Show HN:暂缓。产品仍有注册流程,且当前 Show HN 对不熟悉的账号有临时限制;先积累真实使用和可公开的产品改进记录。
+- BetaList:当前投稿为付费服务,不符合现阶段免费获客原则,因此跳过。
+- 外部发布:不得虚构发送成功;遇到验证码、登录或网络中断时,保留成稿和图片,交由创始人完成最后一次真人确认。
+
+### 今日发送进度
+
+- Reddit 个人主页:已在登录状态下切换到文字帖并填入完整标题、正文和邀请链接;页面停在真人 reCAPTCHA 与 `submit` 之前,已作为接手页保留。尚未声称发布成功。
+- GitHub:已在登录后的公开项目首页核验 README 正常显示,项目描述、功能、隐私边界、协作与融资诉求均可见;无需重复编辑。
+- Cloudflare:Turnstile 小组件为 `Managed`、`No pre-clearance`,后台列表显示 `Likely human 1.04%`。该数据可能包含大量机器人请求,不能直接等同于真实用户失败率;在三个真实海外网络完成注册链路测试前,不降低验证强度。
+
+### 下一检查点
+
+1. 用美国、欧洲和东南亚至少各一个真实浏览器打开首页并完成到注册页,记录是否出现 Cloudflare 拦截。
+2. 发布一条带今日图片的原创功能帖,只选择一个新渠道,链接使用本人的邀请参数。
+3. 发布后 6 小时查看后台的来源访问、注册、首笔债务和有效邀请;没有转化时先检查落地页和加载成功率,不重复刷帖。
+4. 把收到的第一个真实问题整理成次日内容;每天换功能主题,不只重复“请注册”。
+
+## 2026-08-03 每日宣传素材
+
+- 功能主题:真实还款不仅改变进度条,也改变角色身上的铁链、光效、托举负担的气球和宠物状态;强调“一次更新、减轻一点”,不承诺快速上岸。
+- 新图片:`launch-kit/daily-social/2026-08-03-repayment-changes-world.png`
+- 邀请入口:
+- 图片隐私检查:无真实金额、无个人资料、无虚构统计、无排行榜、无保证上岸或奢侈生活暗示。
+
+### 当日后台检查点(10:04)
+
+- 今日独立访客:2;页面打开:2。
+- 今日新增注册:0;首次录债:0;邀请激活:0。
+- 2026-08-02:独立访客、页面打开、新注册、首次录债、邀请激活均为 0。
+- 当前注册账号:1;24 小时活跃:1;近 7 天活跃:1。
+- 当前共同世界角色:3,其中 2 个为待迁移旧角色;债务项共 3;AI 使用共 2 次。
+- 待处理反馈:2;公开故事:0;未结举报:0。
+- 来源归因仍只有直接访问 1 人;Reddit、GitHub、X、邀请链接尚未形成可见转化。
+
+后台数据说明:截至检查时没有新的真实注册或录债,不能把旧角色、测试访问或页面打开数描述为新增用户。
+
+### X 短文案(274 字符)
+
+Debt progress should feel real—not like a leaderboard. In Debt World, confirmed repayments remove chains, add light, help a balloon lift the burden, and energize your pet. I built it to make small steps visible. Beta: https://www.debtworld.org/?ref=SHORE-39BSQL8T&src=friend
+
+### Reddit 首帖透明更新
+
+Builder update: I am now testing how real repayment updates should change the character—not just a progress bar. A confirmed payment can remove part of a chain, add light, help a balloon lift the visible burden, and give the pet more energy. The goal is to make progress feel tangible without turning debt into a competition.
+
+If you test it, I would especially value one answer: which visual feels genuinely encouraging, and which one feels patronizing or too game-like?
+
+### 今日渠道执行状态
+
+- Reddit:公开账号仍只有原始公测帖,显示 1 point、无评论;2026-08-02 的个人主页草稿没有发布。今天已把上述建设性进度回复填入原帖,停在最终 `save` 之前,等待创始人确认公开发送。
+- X:打开 `x.com/home` 后仍是登录/注册页,当前浏览器没有登录状态,因此未填写账号信息、未发送内容。
+- GitHub:项目首页和 Public Beta Issue 已公开,不在无关仓库评论推广。
+- 今日策略:优先完成一个真实可核验的发布动作,再观察 6 小时转化;不因为数据为零而跨社区复制刷屏。
+
+### 10:20 发布与 GitHub 增长方法复盘
+
+- Reddit:原公测帖下的透明构建进度回复已公开并核验,永久链接: 。
+- GitHub:Issue #1 的中英文图文构建日志已获得创始人确认、公开发布并重新读取核验;正文、图片和两条公测入口均可见。永久链接:。
+- 方法参考:InfoQ《我找到了在 GitHub 上获得高星的秘密》:。
+
+对 Debt World 可直接采用的部分:
+
+1. README 第一屏一句话说清产品,并提供可立即体验的入口、截图或演示 GIF。
+2. 不等产品“完成”才公开;每次围绕一个能体验的核心变化发布构建日志。
+3. 每条内容只提一个具体问题,降低真实用户参与反馈的门槛。
+4. 在高度相关社区按规则发布,认真回复每条真实评论;用真实版本里程碑形成下一次传播波次。
+5. 把重复反馈沉淀为产品优先级,而不是追逐所有功能请求。
+
+需要调整或拒绝的部分:
+
+- Debt World 的公开仓库当前是产品与社区主页,不是开源源码仓库;GitHub Star 只能作为信任与关注信号,不能代替访问、注册、首次录债和回访。
+- 不批量跨社区复制、不去无关技术项目评论推广、不把 Star 数作为成功指标。
+- 当前 GitHub 第一优先级不是“求星”,而是增加 20–30 秒实际世界演示 GIF,让访客在 README 第一屏理解产品。
+
+### 下一检查点
+
+1. 获得确认后发布 Reddit 原帖下的开发进度回复,并保存公开链接。
+2. 创始人完成 X 登录后,使用当天新图和 274 字符文案发布首条产品功能帖。
+3. 发布后 6 小时查看 `src=reddit` / `src=x` 的访问、注册、首次录债和反馈。
+4. 若仍为零,优先核验英语首页加载、注册验证和首次建档耗时,而不是立刻扩大渠道数量。
+
+### GitHub README 第一屏演示 GIF(待创始人确认公开上传)
+
+- 成品:`launch-kit/demo-gif/debt-world-walkthrough.gif`
+- 静态预览:`launch-kit/demo-gif/debt-world-walkthrough-preview.png`
+- 六镜头检查图:`launch-kit/demo-gif/debt-world-walkthrough-contact-sheet.jpg`
+- 时长与大小:22.9 秒,800 × 450,约 3.92 MB。
+- 内容:真实站内世界画面,依次聚焦可行走世界、总债务与最大来源、多国家角色、不同还款路径、真实更新影响和匿名数据生长。
+- 隐私处理:登录者个人角色、债务、收入、账户标识和邀请信息已完整遮盖;可见人物均为代码内置的系统演示角色;画面持续标注 `ACTUAL PRODUCT · DEMO WALKERS` 和 `DEMO DATA · NO USER DETAILS`。
+- 建议 README 改动:用该 GIF 替换首屏静态 `og-beta.png`,紧接双语隐私说明和带 `src=github` 的中英文公测入口。完整待发布片段见 `launch-kit/demo-gif/README_INSERT.md`。
+
+### GitHub README 演示 GIF 发布结果(12:56–13:23)
+
+- GIF 已上传到公开仓库根目录:。
+- GIF 提交:。
+- README 首屏已用演示 GIF 替换旧 `og-beta.png`,并加入中英文演示数据与隐私说明。
+- README 提交:。
+- GitHub 来源入口已改为 `https://www.debtworld.org/en?src=github` 与 `https://www.debtworld.org/?src=github`,便于后台识别转化。
+- 公开核验:仓库首页能看到新 GIF、双语说明与两个公测入口;旧静态首图不再出现。
+
+### GitHub 增长方法调研与第一批完善草稿
+
+- 参考 InfoQ 的 Rich 项目推广复盘,以及 Actual Budget、Habitica、AppFlowy、Rich、PostHog、Maybe Finance 的公开 GitHub 项目结构。
+- 已采用:README 第一屏定位、真实产品 GIF、公开构建日志、明确公测入口、隐私边界。
+- 下一缺口:顶部导航、5 分钟测试任务、首个 GitHub Release、About 官网与 Topics、分渠道来源归因。
+- 已准备但尚未公开:`launch-kit/GITHUB_README_GROWTH_INSERT.md`、`ROADMAP.md`、`launch-kit/GITHUB_RELEASE_PUBLIC_BETA_0_1.md`、`launch-kit/GITHUB_GROWTH_ROUND_1.md`。
+- 重要准确性修正:当前产品需要注册后才能进入世界,公开材料不得写成免注册试玩;测试者不得为了测试虚构债务,以免污染未来匿名统计。
+
+### GitHub 第一批增长完善正式发布
+
+- 发布日期:2026-08-03。
+- README 与双语路线图提交:。
+- 首个 Public Beta 预发布版本:。
+- 仓库 About 官网已设为 `https://www.debtworld.org/`,并发布 9 个精准 Topics。
+- 公开核验通过:README 5 分钟体验、`githubreadme` 来源标记、路线图安全边界、`githubroadmap` 来源标记、Release 的 `githubrelease` 来源标记与“不得虚构债务测试”提醒均可见。
+- 后续检查:发布后 6 小时和 24 小时,只查看来源访客、注册、首次真实录债、反馈与邀请激活的聚合变化,不输出用户名、精确债务、收入或私人 AI 对话。
+
+### Reddit 创始人故事候选稿
+
+- 目标:`r/SideProject`,社区定位与项目展示和建设性反馈一致。
+- 主题:为什么要做一个与“人均富豪”错觉相反的匿名债务世界,以及游戏化、隐私、匿名数据生长和 AI 边界之间的真实产品难题。
+- 完整待确认稿:`launch-kit/REDDIT_FOUNDER_STORY_2026-08-03.md`。
+- 配图:`launch-kit/daily-social/2026-08-03-repayment-changes-world.png`。
+- 暂不选择 `r/indiehackers`:其最新规则要求新账号先等待,推广请求需使用 Self Promotion 分类。
+- 发布状态:创始人已确认并提交。帖子链接: 。
+- Reddit 自动筛选结果:账号发布记录明确显示帖子被 Reddit 筛选器移除,未进入 `r/SideProject` 公开信息流;因此不计为有效公开发布或渠道曝光。
+- 已停止动作:不重复发送、不改标题重发、不跨社区复制、不私信版主。后续先积累正常社区参与和账号信誉,再单独准备新的、规则匹配的内容候选并重新请求确认。
+
+### 22:58 入口健康与转化检查
+
+- 今日独立访客从上午的 2 增至 7,页面打开从 2 增至 10;新增注册、首次录债、真实邀请激活仍均为 0。
+- 当前总注册账号 1、24 小时活跃 1、共同世界角色 3(含 2 个待迁移旧角色)、债务项 3、AI 使用 2 次;不把旧角色、管理员访问或页面打开计为新增真实用户。
+- 来源归因仍只有直接访问形成账号和建档;GitHub、Reddit、X 与朋友邀请尚无可见注册转化。
+- 正式中文首页和英文首页均返回 HTTP 200;匿名账号、真人验证和公测状态接口也正常返回,公开注册仍开启且无需邀请码。
+- 风险信号:已登录浏览器的首页可能长期停在“正在打开上岸星球”。根因保护缺口是账号状态请求没有超时,网络异常时前端会无限等待。
+- 已修复:账号状态、登录、注册和退出请求增加 10 秒上限;超时后自动恢复为可操作的账号页,并显示中英文重试提示,不再无限转圈。
+- 验证结果:完整生产构建和 6 项站点测试全部通过。正式发布尚待 Sites 发布通道可用后完成。
+
+下一步骤:先发布入口超时保护并复测中英文注册页;发布成功后观察 6 小时的访问→注册变化。在入口稳定前不增加新的推广渠道。
+
+## 2026-08-04 每日真实增长运营
+
+### 站点健康与聚合变化(10:27)
+
+- 中文首页、英文首页、匿名账号状态、真人验证状态和公测状态接口均返回 HTTP 200;公开注册仍开启、无需邀请码、每日上限 100。
+- 2026-08-03 最终为 7 位独立访客、12 次页面打开、新注册 0、首次录债 0、邀请激活 0。
+- 2026-08-04 截至检查时为 1 位独立访客、1 次页面打开、新注册 0、首次录债 0、邀请激活 0。
+- 总注册账号仍为 1;共同世界角色 3(含 2 个待迁移旧角色);债务项 3;AI 使用 2 次;待处理反馈、待审核故事和未结举报均为 0。
+- 渠道仍只有直接访问形成账号与建档;GitHub、Reddit、X 和朋友邀请没有可见注册转化。
+- 入口超时保护已通过构建与测试,Sites 版本 44 已成功发布到正式站。
+- 发布后复测:中文与英文入口均完成加载并进入真实世界,不再停留在“正在打开”;账号接口、真人验证接口和公测状态接口继续返回 HTTP 200。
+
+### 今日功能主题与原创图片
+
+- 主题:小岸 AI 将混杂的债务、收入和必要开销整理成一个由用户确认的下一步;强调辅助整理,不假装是财务顾问或律师。
+- 新图片:`launch-kit/daily-social/2026-08-04-feature.png`
+- 图片文字:`KIAN HELPS SORT THE PRESSURE` / `Name it. Organize it. Choose one next step.`
+- 隐私检查:无真实用户、金额、收入、后台数据、虚构统计、排行榜、评价或保证上岸结果。
+
+### 今日 X 草稿(236 字符)
+
+Debt can feel like one tangled problem. In Debt World, Kian helps you name debts, income and essential costs, then organize one next step—without pretending to be a financial adviser. Free public beta: https://www.debtworld.org/en?src=x
+
+状态:仅保存草稿,未发送。
+
+### GitHub 今日动作
+
+- README 的定位、演示、5 分钟测试、隐私边界、AI 边界和合作诉求均正常;Issue #1 当前只有 8 月 3 日的一条真实还款视觉构建日志,没有新的外部反馈需要回复。
+- 已准备新的“小岸 AI 边界”图文构建日志候选:`launch-kit/GITHUB_BUILD_LOG_2026-08-04.md`。
+- 目标为我们自己的 `rback37/debt-world` Issue #1;发送前必须展示完整文案、图片预览和隐私检查并获得创始人当次确认。
+
+### Reddit 今日机会
+
+- `r/SideProject` 创始人故事仍被 Reddit 自动筛选器移除;新账号在同一社区换标题重发会增加反垃圾风险。
+- `r/alphaandbetausers` 已有一条公开公测帖;今天没有新的真实评论需要回复,也不重复发布同一产品介绍。
+- 今日 Reddit 不发布、不评论、不私信。后续只在出现真实问题或账号形成正常社区参与后准备新的平台原生候选。
+
+### 需要确认的唯一外部发送动作
+
+- 候选:在 GitHub Issue #1 发布 8 月 4 日“小岸 AI 边界”图文构建日志。
+- 当前状态:等待创始人在当次任务中确认;X 与 Reddit 均不发送。
+
+### 累计真实用户进度
+
+- 可确认注册账号:1。
+- 可确认完成首次真实录债的新账号:0。
+- 可确认邀请激活:0。
+- 不把旧角色、管理员访问、页面打开、被过滤的 Reddit 帖子或 GitHub 浏览计为新增真实用户。
diff --git a/launch-kit/FOUNDING_BUILDER_ISSUES_2026-08.md b/launch-kit/FOUNDING_BUILDER_ISSUES_2026-08.md
new file mode 100644
index 0000000..8a6080c
--- /dev/null
+++ b/launch-kit/FOUNDING_BUILDER_ISSUES_2026-08.md
@@ -0,0 +1,164 @@
+# Founding builder issue set · August 2026
+
+Publication target: `rback37/debt-world`
+
+Every issue is intentionally small enough to claim without production access. Contributors must use synthetic data and must not post exact personal finances, credentials, private conversations, or identifiable screenshots.
+
+## 1. Contribution-page accessibility
+
+**Title:** `[Good first issue] Audit the new contribution page for keyboard and screen-reader clarity`
+
+**Labels:** `good first issue`, `help wanted`, `accessibility`
+
+The new `/contribute` and `/en/contribute` pages should work without a mouse and should make every external GitHub action understandable to assistive technology.
+
+### Small scope
+
+- Check heading order, landmark structure, focus order, link names, visible focus, and keyboard access.
+- Check both Chinese and English routes at desktop and narrow mobile widths.
+- Propose or implement the smallest fixes in `app/ContributePage.tsx` and `app/globals.css`.
+
+### Done when
+
+- All actions can be reached and understood using keyboard navigation.
+- Focus is visible against the current dark-green, acid-yellow, coral, and blue palette.
+- No content is removed solely to make the audit pass.
+- `npm run build` succeeds.
+
+Claim this issue with a short comment describing the browser and assistive technology you can test. Use synthetic examples only.
+
+## 2. Spanish public-beta review
+
+**Title:** `[Localization] Review the first 25 Spanish public-beta strings for clarity and dignity`
+
+**Labels:** `good first issue`, `help wanted`, `translation`
+
+Debt World currently supports Chinese and English. Before adding Spanish routes, we need a human-reviewed starter glossary that avoids debt shaming and works across more than one Spanish-speaking region.
+
+### Small scope
+
+- Propose Spanish versions of 25 short public strings from signup, safety, contribution, and repayment progress.
+- Flag wording that changes meaning across regions rather than forcing one universal phrase.
+- Keep financial and legal language educational; do not invent country-specific legal advice.
+
+### Deliverable
+
+A Markdown table with source string, Spanish proposal, broad region note, and risk/ambiguity note. No code change is required for the first contribution.
+
+Do not include a real debt story or personal financial details. Comment to claim the review before starting.
+
+## 3. Android small-screen test
+
+**Title:** `[Good first issue] Test signup and first world entry on one small Android screen`
+
+**Labels:** `good first issue`, `help wanted`, `testing`, `mobile`
+
+We need one reproducible, privacy-safe walkthrough on an Android phone with a narrow screen.
+
+### Test path
+
+1. Open the public site in a private/incognito session.
+2. Review the registration previews and create a disposable synthetic test account.
+3. Choose a country, complete or skip optional profile fields, and enter the world.
+4. Check text size, horizontal overflow, action discovery, character controls, and zoom controls.
+5. Delete the synthetic account when finished.
+
+### Deliverable
+
+- Device family, Android version, browser, viewport or screen size.
+- Reproduction steps for each problem.
+- Privacy-safe screenshots with usernames and any financial values removed or synthetic.
+
+Never test another user's account or publish cookies, passwords, exact personal finances, or private conversations.
+
+## 4. Slow-network account audit
+
+**Title:** `[Testing] Audit signup and login recovery on a slow or high-latency connection`
+
+**Labels:** `help wanted`, `testing`, `reliability`
+
+Debt World is intended for global use, including slower or unstable connections. We need a focused audit of loading, timeout, retry, and duplicate-submit behavior.
+
+### Small scope
+
+- Test registration and login with browser network throttling or a naturally slow connection.
+- Check whether the account screen appears after a timeout, error messages remain understandable, and buttons prevent duplicate submissions.
+- Test one successful retry without reloading when possible.
+
+### Done when
+
+The report includes timing, browser, steps, expected behavior, actual behavior, and one suggested smallest fix. Use only a disposable synthetic account and never attach raw responses containing secrets or identifiers.
+
+## 5. Brazil debt-category map
+
+**Title:** `[Regional review] Map common debt categories in Brazil without personal data`
+
+**Labels:** `good first issue`, `help wanted`, `research`, `translation`
+
+The current global taxonomy needs human review before it can represent Brazil responsibly.
+
+### Small scope
+
+- Review the current broad categories: mortgage, credit card, education, medical, vehicle, personal, business, BNPL, family/friends, and other.
+- Identify missing or misleading high-level categories used in Brazil.
+- Provide neutral Portuguese labels and one reliable public source for terminology when available.
+- Note which categories should stay grouped to reduce re-identification risk.
+
+Do not submit a personal debt story, lender account, exact amount, or individualized legal/financial advice. The result is a category proposal, not an automatic production change.
+
+## 6. Mobile zoom and action discovery
+
+**Title:** `[Design] Improve mobile world zoom and top-action discoverability`
+
+**Labels:** `help wanted`, `design`, `mobile`, `ux`
+
+The shared world has several important actions—planner, community, invite, build, feedback, account, safety, and language. On narrow screens the horizontal action strip can hide important controls.
+
+### Small scope
+
+- Review the current mobile header and world zoom controls.
+- Propose one low-complexity interaction that keeps the world visible and makes essential actions discoverable.
+- Include states for first visit and returning use.
+
+### Deliverable
+
+A privacy-safe wireframe, annotated screenshot using synthetic content, or a small code prototype. Keep admin controls, production data, and private financial content out of the design.
+
+Acceptance prioritizes readable labels, thumb reach, keyboard access, and no overlap with the real-life rules panel.
+
+## 7. Privacy-copy review
+
+**Title:** `[Privacy review] Audit contribution and public-story wording for accidental oversharing`
+
+**Labels:** `help wanted`, `privacy`, `content`
+
+Debt World asks users and contributors to share only what is needed. We need a wording audit that catches moments where someone might misunderstand a public field as private.
+
+### Small scope
+
+- Review `/contribute`, `/en/contribute`, the community story composer, and GitHub templates.
+- Identify any sentence that could encourage names, exact amounts, account details, private conversations, or unauthorized stories.
+- Suggest shorter, clearer alternatives in Chinese or English.
+
+### Done when
+
+The review lists the location, current wording, risk, and proposed wording. This is a product-language review, not legal advice. Do not include real user text or production screenshots.
+
+## 8. Ten-minute local setup checklist
+
+**Title:** `[Good first issue] Add a 10-minute Windows, macOS, and Linux setup checklist`
+
+**Labels:** `good first issue`, `help wanted`, `documentation`
+
+The README contains the commands, but a first-time contributor still needs a short path from clone to a verified local page.
+
+### Small scope
+
+- Document prerequisites for Node.js 22.13+ and the existing npm workflow.
+- Add separate notes for PowerShell, macOS, and Linux only where commands differ.
+- Explain how to use synthetic test data and which local files must never be committed.
+- End with `npm run build`, `npm run lint`, and the test command.
+
+### Done when
+
+A new contributor can clone, install, start, verify, and stop the app without production credentials. Do not add real environment values or secrets to the documentation.
diff --git a/launch-kit/GITHUB_BUILD_LOG_2026-08-04.md b/launch-kit/GITHUB_BUILD_LOG_2026-08-04.md
new file mode 100644
index 0000000..9043c04
--- /dev/null
+++ b/launch-kit/GITHUB_BUILD_LOG_2026-08-04.md
@@ -0,0 +1,54 @@
+# GitHub build-log candidate · 2026-08-04
+
+Status: prepared locally only. Do not publish until the founder confirms this exact target, copy, image, and privacy check in the current task.
+
+## Target
+
+- Repository: `rback37/debt-world`
+- Thread: Issue #1 — Public Beta
+- Action: one new top-level build-log comment
+- Image: `launch-kit/daily-social/2026-08-04-feature.png`
+
+## Exact copy
+
+## Build log — August 4, 2026: Kian helps sort pressure into one next step
+
+Debt can arrive as one tangled description: several balances, different due dates, income that changes, essential costs, and no obvious place to begin.
+
+This iteration tests a narrower role for Kian AI. Kian can help a user:
+
+- name debts, income, and essential costs;
+- separate known facts from missing information;
+- organize multiple obligations without merging them into one misleading number;
+- draft a few educational repayment lenses; and
+- choose one small next step for the user to confirm.
+
+Kian does not connect to a bank, alter balances automatically, recommend a new loan, make local legal conclusions, or act as a financial adviser or lawyer. Exact personal data and private conversations do not enter the public map.
+
+The question for this build is:
+
+> At what moment would this kind of AI organization feel genuinely useful—and at what moment would it start to feel too authoritative?
+
+Public beta: https://www.debtworld.org/en?src=github
+
+---
+
+## 2026 年 8 月 4 日构建日志:让小岸把压力整理成一个下一步
+
+真实的债务处境往往不是一张整齐的表格,而是一段混在一起的描述:多笔余额、不同还款日、波动收入、必要开销,以及“不知道先做什么”。
+
+这次测试的是更克制的小岸 AI:帮助用户区分债务、收入和必要开销,标出缺失信息,把多项义务分别整理,并提供几种教育性的还款观察角度。最后一步始终由用户自己确认。
+
+小岸不会连接银行、自动修改余额、推荐新贷款、代替当地法律判断,也不是财务顾问或律师。精确个人数据和私人对话不会进入公共地图。
+
+这次只问一个问题:**这种 AI 整理在什么时刻会真正有帮助,又在什么时刻会显得过于权威?**
+
+中文公测:https://www.debtworld.org/?src=github
+
+## Privacy and claims check
+
+- No real user, account identifier, personal amount, income, private conversation, or admin data.
+- No fabricated traffic, registration, repayment result, testimonial, ranking, or outcome claim.
+- No promise of debt reduction and no financial or legal-advice claim.
+- Founder/product relationship is clear from the existing Issue context.
+- The image contains only conceptual categories and no personal financial data.
diff --git a/launch-kit/GITHUB_GROWTH_ROUND_1.md b/launch-kit/GITHUB_GROWTH_ROUND_1.md
new file mode 100644
index 0000000..382f2da
--- /dev/null
+++ b/launch-kit/GITHUB_GROWTH_ROUND_1.md
@@ -0,0 +1,77 @@
+# GitHub growth round 1
+
+Prepared: 2026-08-03
+
+Published: 2026-08-03
+
+- README and roadmap commit:
+- Public beta release:
+- Repository homepage and nine approved Topics were verified through the public GitHub API after publication.
+
+## Public targets
+
+1. Repository metadata for `rback37/debt-world`.
+2. `README.md` top navigation and five-minute testing path.
+3. New bilingual public roadmap: `ROADMAP.md`.
+4. First GitHub Release: `public-beta-0.1`.
+
+No unrelated repository comments, direct messages, mass promotion, fake stars, or cross-community copy-pasting are included.
+
+## About metadata
+
+- Website: `https://www.debtworld.org/`
+- Keep current description: `A walkable anonymous debt world for seeing real financial pressure and tracking repayment progress.`
+- Proposed Topics:
+ - `debt`
+ - `debt-tracker`
+ - `debt-repayment`
+ - `personal-finance`
+ - `financial-wellbeing`
+ - `gamification`
+ - `privacy-first`
+ - `anonymous-community`
+ - `multilingual`
+
+Do not add `mental-health`, `financial-advice`, `legal-advice`, `loan`, or `debt-relief`; those would create inaccurate product positioning.
+
+## README change
+
+Use the exact blocks in `launch-kit/GITHUB_README_GROWTH_INSERT.md`.
+
+The new path converts a GitHub visitor into one bounded test without asking for private financial disclosure on GitHub. It also distinguishes truthful debt entry from navigation-only testing so public-beta tests do not contaminate future anonymous aggregates.
+
+## Roadmap change
+
+Publish the prepared `ROADMAP.md`. It separates current reliability work, the next privacy-gated features, later scale-dependent ideas, and product lines that will not be crossed for growth. Roadmap entry links use `src=githubroadmap`.
+
+## Release change
+
+Use the exact draft in `launch-kit/GITHUB_RELEASE_PUBLIC_BETA_0_1.md`.
+
+The release creates a reusable public milestone for future Reddit, X, and relevant builder-community posts. It is not a Show HN submission; the current product still requires registration, while Show HN recommends making the product easy to try without sign-up barriers.
+
+## Measurement window
+
+Check 6 hours and 24 hours after publication:
+
+- unique visitors from `githubreadme` and `githubrelease`;
+- registrations from each source;
+- first truthful debt entry;
+- product feedback submission;
+- invitation activation, if any;
+- GitHub stars or watchers only as secondary attention signals.
+
+Never expose usernames, exact debt, income, private AI conversations, or other identifiable user data in the report.
+
+## Confirmation gate
+
+Before publishing, show the founder:
+
+- exact repository metadata;
+- complete README insert;
+- complete bilingual roadmap;
+- complete Release title and body;
+- existing walkthrough GIF preview;
+- privacy and claims checklist.
+
+Founder confirmation was received before publication. The public verification confirmed `githubreadme`, `githubroadmap`, and `githubrelease` source markers, the no-fake-debt warning, and the roadmap's non-negotiable safety boundaries.
diff --git a/launch-kit/GITHUB_PUBLIC_README_DRAFT.md b/launch-kit/GITHUB_PUBLIC_README_DRAFT.md
new file mode 100644
index 0000000..80f5cce
--- /dev/null
+++ b/launch-kit/GITHUB_PUBLIC_README_DRAFT.md
@@ -0,0 +1,108 @@
+> Historical pre-launch README draft. Do not publish this file directly. The current GitHub growth update is defined in `GITHUB_README_GROWTH_INSERT.md` and must be applied to the live README only after founder confirmation.
+
+# 上岸星球 · Debt World
+
+
+
+> A shared, walkable world for honest debt journeys.
+> 一个会随着真实匿名数据不断生长的债务世界。
+
+[Try the public beta](https://www.debtworld.org/) · [Safety & privacy](https://www.debtworld.org/en/safety) · [中文说明](#中文说明)
+
+## Why Debt World exists
+
+Social media can make ordinary people feel as if everyone else is rich. Debt World reverses that illusion. It turns self-reported debts, income, living costs, interest, due dates, and real payment updates into an anonymous character and a world people can explore together.
+
+This is not a debt leaderboard and it does not promise a shortcut out. The goal is to make pressure legible, reduce isolation, and help people find realistic next steps.
+
+## What the current beta can do
+
+- Organize multiple debts through conversation or manual entry.
+- Track original amount, current balance, APR, minimum payment, due date, status, and repayment method per debt.
+- Compare income, essential living costs, fixed payments, and month-left cash flow.
+- Show highest-interest, smallest-balance, and cash-flow-safety repayment lenses.
+- Update progress only after a person confirms a real payment and latest principal balance.
+- Turn debt sources and progress into visible character burdens, chains, labels, and light.
+- Explore a zoomable world of reviewed anonymous stories and send fixed, safe encouragement.
+- Select country and display currency without relying on IP location.
+- Add, adjust, export, or permanently delete account and character data.
+- Use Chinese or English; more languages will be added only with real users and human review.
+
+
+
+## Privacy and safety by design
+
+- No real name, phone number, government ID, bank card, or precise address is required.
+- No bank is currently connected; financial data is self-reported.
+- Exact debt, income, expense, and AI conversation content does not enter the public map.
+- Each debt is private by default. Public sharing is limited to anonymous ranges.
+- Public stories require separate consent, sensitive-detail removal, and moderation.
+- No stranger direct messages, loans, transfers, crowdfunding, collection leads, or paid debt-relief offers.
+- Aggregate data remains locked until a privacy sample threshold is met.
+- Users can export account data, withdraw stories, and permanently delete their account and character.
+
+Read the full [English safety center](https://www.debtworld.org/en/safety) or [中文安全中心](https://www.debtworld.org/safety).
+
+## What Kian AI does—and does not do
+
+Kian can organize a free-form description into a draft, calculate simple interest references from user-entered rates, compare repayment lenses, and identify one missing fact or next step. Every draft must be confirmed by the user.
+
+Kian is not a financial adviser, lawyer, doctor, credit bureau, lender, debt-relief company, or crisis service. It does not guarantee repayment outcomes, recommend new loans, or make local legal conclusions.
+
+## Public beta status
+
+The product is in staged public beta. Registration is open without an invitation code, with human verification, a daily signup limit, moderation, reporting, and an emergency pause. The live site is free during beta.
+
+## Help shape the world
+
+Useful contributions are not limited to code:
+
+- Report a confusing or unsafe interaction.
+- Test slow networks, older phones, keyboards, and screen readers.
+- Review Chinese or English wording.
+- Propose a respectful name for a missing debt category.
+- Help translate product, privacy, and crisis language after a language cohort opens.
+- Review privacy, accessibility, financial education, or consumer-safety boundaries.
+
+Never include real debt amounts, passwords, bank details, identity documents, private conversations, or complete statements in a GitHub issue.
+
+## Looking for collaborators and responsible support
+
+Debt World is an early public-benefit product being built with a very small budget. We welcome product, game-world, accessibility, privacy, moderation, consumer-safety, and native-language collaborators. We are also open to responsible early-stage partners, grants, or funding that protect user privacy and never turn people in debt into sales leads.
+
+## Local development
+
+Requires Node.js 22.13 or newer.
+
+```bash
+npm install
+npm run dev
+```
+
+Validation:
+
+```bash
+npm run lint
+npm test
+```
+
+## Project documents
+
+- [Product plan](PRODUCT_PLAN.md)
+- [Progress tracker](PROJECT_PROGRESS.md)
+- [World growth system](WORLD_GROWTH_SYSTEM.md)
+- [Contributing](CONTRIBUTING.md)
+
+## Responsible disclosure
+
+Do not open public issues containing user data or an exploitable security detail. Use the private reporting method described in `SECURITY.md` after it is published.
+
+## License
+
+The source license has not yet been selected. Do not publish the repository as open source until the owner chooses and adds a license.
+
+## 中文说明
+
+上岸星球想反过来对抗“人均富豪”的网络错觉。用户可以把房贷、信用卡、学贷、医疗、经营、亲友借款等真实压力整理成匿名角色、进度和现实时间轴,也可以看到经过授权和审核的普通人故事。
+
+它不是欠款排行榜,不连接银行,不推荐贷款,不提供债务减免服务,也不保证任何人快速上岸。精确数据默认私密,用户可以导出和彻底删除自己的记录。
diff --git a/launch-kit/GITHUB_PUBLIC_README_FINAL.md b/launch-kit/GITHUB_PUBLIC_README_FINAL.md
new file mode 100644
index 0000000..f921e7f
--- /dev/null
+++ b/launch-kit/GITHUB_PUBLIC_README_FINAL.md
@@ -0,0 +1,102 @@
+# Debt World · 上岸星球
+
+> A shared, walkable world for honest debt journeys.
+> 一个会随着真实匿名数据不断生长的债务世界。
+
+[Live beta](https://www.debtworld.org/en?src=githubreadme) · [23-second demo](#walk-the-world-in-23-seconds--23-秒看懂上岸星球) · [5-minute test](#test-debt-world-in-5-minutes--5-分钟体验) · [Roadmap](ROADMAP.md) · [Public build log](https://github.com/rback37/debt-world/issues/1) · [Contribute](CONTRIBUTING.md) · [Safety](https://www.debtworld.org/en/safety)
+
+## Walk the world in 23 seconds · 23 秒看懂上岸星球
+
+
+
+> Actual product capture. Every visible walker uses system demo data. No real user debt, income, account identity, or private AI conversation is shown.
+>
+> 真实产品画面。所有可见角色均为系统演示数据,不展示真实用户的债务、收入、账户身份或私人 AI 对话。
+
+[**Start the 5-minute test**](https://www.debtworld.org/en?src=githubreadme) · [开始 5 分钟体验](https://www.debtworld.org/?src=githubreadme) · [Safety & privacy](https://www.debtworld.org/en/safety) · [中文安全说明](https://www.debtworld.org/safety)
+
+## Test Debt World in 5 minutes · 5 分钟体验
+
+1. Watch the walkthrough above and read the privacy boundary before registering.
+2. Open the beta and create an anonymous username and password. No email, phone number, or legal name is required.
+3. Choose a country and language, enter the shared world, and look around before deciding whether to enter financial information.
+4. If you feel comfortable, privately add one truthful debt or cash-flow item. If you would rather not enter financial data, skip this step and test navigation, keyboard controls, language, readability, or accessibility instead.
+5. Open **Feedback** in the product and answer one question: **During your first visit, which step felt most confusing, intrusive, or made you want to leave?**
+
+中文:先看上方动图和隐私说明,再用匿名用户名注册。进入世界后可以先观察,不必立即填写财务信息;愿意时只录入一项真实且私密的负债或现金流,不愿填写也可以只测试地图、键盘、语言和可读性。最后在产品内的“反馈”入口回答:**第一次进入时,哪一步最让你困惑、不安或想退出?**
+
+Please do not invent debt records just to test the form; fake records would distort future anonymous aggregates. Never post personal debt amounts, income, passwords, bank details, identity documents, or private AI conversations on GitHub.
+
+## Why it exists
+
+Social media can make ordinary people feel as if everyone else is rich. Debt World reverses that illusion. It helps people map real debt pressure, see repayment progress clearly, and discover that they are not alone.
+
+上岸星球想反过来对抗“人均富豪”的网络错觉:把房贷、信用卡、学贷、医疗、经营、亲友借款等真实压力整理成匿名角色与现实进度,让普通人看见更接近真实的世界。
+
+It is not a debt leaderboard and it does not promise a shortcut out. The goal is to make pressure legible, reduce isolation, and help people find realistic next steps.
+
+## What the public beta can do
+
+- Enter one shared world that grows as new anonymous debt patterns appear.
+- Organize multiple debts through conversation or manual entry.
+- Track balance, APR, minimum payment, due date, income, living costs, and confirmed payment updates.
+- Compare highest-interest, smallest-balance, and cash-flow-safety repayment lenses.
+- Turn debt sources and progress into visible burdens, chains, labels, light, balloons, and clouds.
+- Explore a zoomable world of reviewed anonymous stories and send fixed, safe encouragement.
+- Select a country and understand amounts in the selected currency.
+- Add, adjust, export, or permanently delete account and character data.
+- Use Chinese or English; more languages will follow real user cohorts and human review.
+
+## Privacy and safety by design
+
+- No legal name, phone number, government ID, bank card, or precise address is required.
+- No bank is connected. Financial data is self-reported.
+- Exact debt, income, expenses, passwords, and private AI conversations never enter the public map.
+- Public stories require separate consent, sensitive-detail removal, and moderation.
+- No stranger direct messages, lending, transfers, crowdfunding, collection leads, or paid debt-relief offers.
+- Users can export account data, withdraw stories, and permanently delete their account and character.
+- The sole owner admin sees operational counts, account status, submitted feedback, and moderation queues—not passwords or private AI conversations.
+
+## What Kian AI does—and does not do
+
+Kian can organize a free-form description into a draft, calculate simple interest references from user-entered rates, compare repayment lenses, and identify missing facts or next steps. Every draft must be confirmed by the user.
+
+Kian is not a financial adviser, lawyer, doctor, credit bureau, lender, debt-relief company, or crisis service. It does not guarantee outcomes, recommend new loans, or make local legal conclusions.
+
+## Public beta status
+
+Public registration is open at [www.debtworld.org](https://www.debtworld.org/). No invitation code is required. Human verification, daily registration limits, moderation, reporting, and an emergency signup pause remain active while the product is tested.
+
+## Help shape the world
+
+- Report a confusing or unsafe interaction.
+- Test slow networks, older phones, keyboards, and screen readers.
+- Review Chinese or English wording.
+- Propose a respectful name for a missing debt category.
+- Help translate product, privacy, and crisis language after a language cohort opens.
+- Review accessibility, privacy, financial-education, or consumer-safety boundaries.
+
+Use GitHub Issues for product bugs and ideas only. **Never post real debt amounts, passwords, bank details, identity documents, private conversations, or complete statements.** Private personal feedback belongs in the website’s Feedback panel.
+
+## Looking for collaborators and responsible support
+
+Debt World is an early public-benefit product being built with a very small budget. We welcome product, game-world, accessibility, privacy, moderation, consumer-safety, and native-language collaborators.
+
+We are also open to responsible early-stage partners, grants, or funding that protect user privacy and never turn people in debt into sales leads.
+
+## Repository scope
+
+This public repository is the project’s product-and-community home. Production source code, infrastructure settings, secrets, private operating notes, and user data are intentionally not published here. A source license has not been selected, so this repository must not be described as open source.
+
+- [Roadmap](ROADMAP.md)
+- [Contributing](CONTRIBUTING.md)
+- [Security](SECURITY.md)
+- [Code of conduct](CODE_OF_CONDUCT.md)
+
+## 中文说明
+
+上岸星球不是比惨、欠款排行榜、贷款平台或债务减免机构。精确数据默认私密;公开故事需要单独授权并经过审核。小岸只提供教育性整理,不替代财务顾问、律师、医生或当地官方服务。
+
+目前正在寻找产品、游戏化、无障碍、隐私、审核、消费者保护、翻译方向的协作者,也欢迎不牺牲用户隐私、不把负债用户变成销售线索的早期支持、赠款或融资合作。
+
+公开测试已经开放,无需邀请码:[进入上岸星球](https://www.debtworld.org/?src=githubreadme)。
diff --git a/launch-kit/GITHUB_README_GROWTH_INSERT.md b/launch-kit/GITHUB_README_GROWTH_INSERT.md
new file mode 100644
index 0000000..0c1a440
--- /dev/null
+++ b/launch-kit/GITHUB_README_GROWTH_INSERT.md
@@ -0,0 +1,45 @@
+# Debt World GitHub README growth insert
+
+Status: published after founder confirmation on 2026-08-03. The exact merged README is archived in `GITHUB_PUBLIC_README_FINAL.md`.
+
+## 1. Top navigation
+
+Place this directly below the opening English and Chinese mission lines:
+
+```md
+[Live beta](https://www.debtworld.org/en?src=githubreadme) · [23-second demo](#walk-the-world-in-23-seconds--23-秒看懂上岸星球) · [5-minute test](#test-debt-world-in-5-minutes--5-分钟体验) · [Roadmap](ROADMAP.md) · [Public build log](https://github.com/rback37/debt-world/issues/1) · [Contribute](CONTRIBUTING.md) · [Safety](https://www.debtworld.org/en/safety)
+```
+
+## 2. Replace the current beta-link row
+
+Replace the existing beta-link row beneath the walkthrough privacy note with:
+
+```md
+[**Start the 5-minute test**](https://www.debtworld.org/en?src=githubreadme) · [开始 5 分钟体验](https://www.debtworld.org/?src=githubreadme) · [Safety & privacy](https://www.debtworld.org/en/safety) · [中文安全说明](https://www.debtworld.org/safety)
+```
+
+## 3. Five-minute test section
+
+Insert this immediately after the replacement link row and before `Why it exists`:
+
+```md
+## Test Debt World in 5 minutes · 5 分钟体验
+
+1. Watch the walkthrough above and read the privacy boundary before registering.
+2. Open the beta and create an anonymous username and password. No email, phone number, or legal name is required.
+3. Choose a country and language, enter the shared world, and look around before deciding whether to enter financial information.
+4. If you feel comfortable, privately add one truthful debt or cash-flow item. If you would rather not enter financial data, skip this step and test navigation, keyboard controls, language, readability, or accessibility instead.
+5. Open **Feedback** in the product and answer one question: **During your first visit, which step felt most confusing, intrusive, or made you want to leave?**
+
+中文:先看上方动图和隐私说明,再用匿名用户名注册。进入世界后可以先观察,不必立即填写财务信息;愿意时只录入一项真实且私密的负债或现金流,不愿填写也可以只测试地图、键盘、语言和可读性。最后在产品内的“反馈”入口回答:**第一次进入时,哪一步最让你困惑、不安或想退出?**
+
+Please do not invent debt records just to test the form; fake records would distort future anonymous aggregates. Never post personal debt amounts, income, passwords, bank details, identity documents, or private AI conversations on GitHub.
+```
+
+## Privacy and accuracy check
+
+- Does not claim that a guest demo exists; registration is currently required.
+- Does not ask testers to disclose debt in GitHub Issues or comments.
+- Does not promise repayment, financial improvement, legal outcomes, or AI accuracy.
+- Explicitly tells testers not to create fake debt records.
+- Uses `src=githubreadme` on beta entry links for exact aggregate source attribution.
diff --git a/launch-kit/GITHUB_RELEASE_PUBLIC_BETA_0_1.md b/launch-kit/GITHUB_RELEASE_PUBLIC_BETA_0_1.md
new file mode 100644
index 0000000..5a67e84
--- /dev/null
+++ b/launch-kit/GITHUB_RELEASE_PUBLIC_BETA_0_1.md
@@ -0,0 +1,59 @@
+# GitHub Release draft
+
+- Proposed tag: `public-beta-0.1`
+- Proposed title: `Debt World Public Beta 0.1 — Walk the shared debt world`
+- Target repository: `rback37/debt-world`
+- Status: published after founder confirmation on 2026-08-03 at .
+
+---
+
+# Debt World Public Beta 0.1 — Walk the shared debt world
+
+Debt World is a walkable anonymous world for seeing the financial pressure behind ordinary lives and tracking real repayment progress without turning debt into a leaderboard.
+
+
+
+## What you can try
+
+- Create a private account without an email, phone number, or legal name.
+- Enter one shared world with clearly labeled system demo walkers.
+- Organize multiple debts, balances, APRs, due dates, minimums, repayment methods, income, and essential living costs.
+- View amounts in the selected country's currency.
+- Confirm a payment only after it really happened and enter the latest principal balance.
+- See progress affect labels, chains, light, balloons, burdens, and the character's surroundings.
+- Use Kian to structure a free-form description, identify missing facts, and compare educational repayment lenses.
+- Send fixed, reviewed encouragement without stranger direct messages.
+
+## What this beta does not do
+
+- It does not connect to a bank or automatically verify balances.
+- It does not rank a real person by who owes the most.
+- It does not sell loans, debt relief, collection leads, or financial products.
+- Kian is not a financial adviser, lawyer, doctor, lender, credit bureau, or crisis service, and it does not guarantee an outcome.
+- Registration is currently required; a no-signup guest demo is not available yet.
+- Chinese and English are available now. More languages require a real user cohort and human review.
+- Real aggregate debt-pattern data stays locked until the privacy sample threshold is met.
+
+## A five-minute public-beta test
+
+1. Read the privacy boundary and watch the walkthrough.
+2. Create an anonymous account at [debtworld.org](https://www.debtworld.org/en?src=githubrelease).
+3. Enter the world and explore before deciding whether to add financial information.
+4. If comfortable, add one truthful private debt or cash-flow item. Otherwise test navigation, keyboard controls, language, readability, or accessibility.
+5. Use the product's Feedback panel to answer the question below.
+
+> **During your first visit, which step felt most confusing, intrusive, or made you want to leave?**
+
+Please do not invent debt records for testing, and never post personal debt amounts, income, passwords, bank details, identity documents, or private AI conversations on GitHub.
+
+[Enter the English beta](https://www.debtworld.org/en?src=githubrelease) · [进入中文公测](https://www.debtworld.org/?src=githubrelease) · [Safety & privacy](https://www.debtworld.org/en/safety) · [Public build log](https://github.com/rback37/debt-world/issues/1)
+
+---
+
+## Release privacy and claim check
+
+- Visible walkthrough characters are system demo walkers.
+- No real user count, debt amount, income, testimonial, or conversion figure is claimed.
+- No repayment, legal, health, investment, or AI outcome is promised.
+- Personal feedback is directed to the product rather than public GitHub comments.
+- All release entry links use `src=githubrelease` for exact aggregate attribution.
diff --git a/launch-kit/IMAGE_PROMPTS.md b/launch-kit/IMAGE_PROMPTS.md
new file mode 100644
index 0000000..b24a33e
--- /dev/null
+++ b/launch-kit/IMAGE_PROMPTS.md
@@ -0,0 +1,20 @@
+# 宣传图生成记录
+
+生成方式:Codex 内置 ImageGen。全部为项目专用原创素材,未使用第三方图片参考。
+
+## `debt-world-global-hero.png`
+
+Use case: ads-marketing. Global public-beta campaign hero, wide landscape. A tactile paper-and-clay miniature planet map with winding paths, diverse anonymous people on soft glowing rings, debt burdens represented by a house, card, book, medical symbol, car and handshake, chain links reducing toward a warm shoreline, and a friendly small golden dog guide. Premium stop-motion indie-game campaign style. Deep charcoal green, parchment, warm orange, muted blue and lime-gold. Dark negative space on the left. No text, numbers, currency, logos, cash piles, luxury imagery, shame, stereotypes or duplicate characters.
+
+## `debt-world-social-square.png`
+
+Use case: ads-marketing. Square social image showing one anonymous clay character calmly organizing five separate burdens—house, credit card, book, medical cross and handshake—connected to progress arcs. Heavy chain links behind, one lighter link ahead, golden dog pointing to a glowing path, and distant diverse people showing community. Premium handcrafted diorama. Safe headline and CTA margins. No text, numbers, currency, logos, cash piles, luxury imagery or shame.
+
+## `debt-world-journey-vertical.png`
+
+Use case: ads-marketing. Vertical social story with the same anonymous character at four stages on a path from a dim debt district to an open shoreline: carrying several burdens and chains, organizing them with the golden dog guide, recording a real payment as chains reduce, and reaching the shore with only an open link. Diverse people on nearby paths. Honest-to-hopeful lighting transition, no miracle or wealth promise. No text, numbers, logos, currency, banks, cash piles or superhero transformation.
+
+## `debt-world-public-beta-en.png`
+
+Use case: text-localization. Edit only the left negative space of `debt-world-global-hero.png`. Add exactly: “DEBT WORLD”, “PUBLIC BETA”, and “REAL DEBT. REAL PROGRESS. NO SHAME.” Use large condensed off-white typography, a restrained lime-gold beta label and smaller spaced tagline. Preserve all original characters, burdens, chains, dog, map, lighting and shoreline. No additional text, logos, URLs, QR codes or watermark.
+
diff --git a/launch-kit/PRESS_KIT_ZH_EN.md b/launch-kit/PRESS_KIT_ZH_EN.md
new file mode 100644
index 0000000..8f84a60
--- /dev/null
+++ b/launch-kit/PRESS_KIT_ZH_EN.md
@@ -0,0 +1,196 @@
+# 上岸星球 / Debt World 公测媒体与产品资料
+
+## 1. 一句话定位
+
+### 中文
+
+一个可以行走的匿名债务世界:把债务、压力和真实还款进度放到看得见的地方,也看见世界各地普通人的真实生活。
+
+### English
+
+A walkable anonymous debt world that turns financial pressure into a visible journey—and shows that ordinary people everywhere are carrying more than social media reveals.
+
+## 2. 极短介绍
+
+### 20 字中文
+
+看见真实压力,也看见正在前进的人。
+
+### 60 字中文
+
+与小岸聊聊,把多笔债务整理成匿名角色、进度条和现实还款路线,在世界里找到处境相似的人。
+
+### English tagline
+
+See the debt. Find your next step. Know you are not alone.
+
+### English one-liner
+
+Turn real debts into a private, game-like journey and explore reviewed anonymous stories from people moving forward around the world.
+
+## 3. 30 秒产品介绍
+
+### 中文
+
+社交网络让普通人很容易产生“别人都很有钱,只有我过得不好”的错位感。上岸星球把这个逻辑反过来:用户先选择国家和货币,再通过文字或语音把房贷、信用卡、学贷、医疗、经营、亲友借款等压力拆成多笔债务。每笔债务会变成角色身上的标签、背负物、锁链、还款日和真实进度。用户可以在世界里行走,看到经过授权和审核的匿名故事,送出固定的鼓励,同时保留导出和彻底删除数据的权利。
+
+### English
+
+Social media can make ordinary people feel as if everyone else is rich. Debt World reverses that illusion. People choose their country and currency, then use text or browser voice to organize mortgages, cards, student loans, medical debt, business debt, money owed to friends, and other real pressures. Each debt becomes a visible label, burden, chain, due date, and progress track around an anonymous character. People can walk through a growing world, encounter reviewed anonymous stories, send safe encouragement, and keep the right to export or permanently delete their data.
+
+## 4. 为什么存在
+
+上岸星球不是为了把欠债变成娱乐,也不是为了制造“比谁更惨”的排行榜。它要解决三个问题:
+
+1. 把模糊、持续的压力拆成可以看见和更新的事实。
+2. 纠正“人均富豪”的社交媒体错觉,让用户知道负债不是个人道德失败。
+3. 帮用户找到与自己处境相似的真实方法,同时避免陌生人借款、收费引流和危险建议。
+
+Debt World is not designed to gamify suffering or rank who owes the most. It exists to make pressure legible, counter the online illusion of universal wealth, and help people discover realistic next steps without enabling loans, solicitation, or predatory advice.
+
+## 5. 当前核心功能
+
+1. **对话式整理**:与小岸交谈,自由描述欠多少、欠在哪里、为什么欠、每月能还多少、收入开销和当前计划。
+2. **多笔债务档案**:每笔债务独立记录类型、原始金额、余额、币种、利率、最低还款、还款日、状态和方式,可单独编辑。
+3. **现实进度**:只有用户确认真实付款并填写付款后的最新本金,进度才变化;不把整笔月供误当本金。
+4. **可视化角色**:头顶完整显示总欠款;最大来源决定背负物,余额和进度影响衣着、体型及锁链层级。
+5. **收支与路线**:比较收入、生活开销、固定月还和月底余量,并展示高利率优先、最小余额优先、现金流安全三种思路。
+6. **可行走世界**:支持键盘、触控、缩放和拖动;靠近角色后查看匿名债务构成与进度。
+7. **匿名社区**:公开故事必须单独授权、清除敏感信息并经过审核;只能发送固定鼓励,不能私信借钱。
+8. **跨国理解**:国家与展示货币由用户自己选择,不依赖 IP;金额按参考汇率换算,同时保留原币。
+9. **隐私控制**:精确个人数据不进入公开地图;支持账号登录、导出、撤回故事和彻底删除。
+10. **世界成长**:达到隐私样本门槛后才显示匿名聚合;未来由真实新增债务方向长出新的建筑和社区。
+
+## 6. 用户第一次进入会发生什么
+
+1. 选择国家/地区和希望看到的货币。
+2. 阅读世界规则,知道这里不做羞辱榜、贷款和收费引流。
+3. 与金条狗“小岸”聊天或手动填写自己的情况。
+4. 核对 AI 整理出的待确认内容;系统不会自动替用户保存猜测。
+5. 生成自己的角色、债务标签、现金流画像和现实时间轴。
+6. 创建账号后可跨设备保存角色和进度,并进入同一个共享大世界。
+
+## 7. AI 能做和不能做什么
+
+### 能做
+
+- 把自由描述整理成待确认的多笔债务草稿。
+- 计算已填写利率对应的简单月利息参考。
+- 对比不同还款顺序,指出还缺哪些关键数据。
+- 把焦虑拆成一个今天能完成的小动作。
+- 帮用户整理需要向债权方、监管机构或专业人士确认的问题。
+
+### 不能做
+
+- 不自动修改余额,不猜未知金额、利率或法律结论。
+- 不保证多久上岸,不推荐新贷款或高风险投资。
+- 不冒充持牌财务顾问、律师、医生或危机服务。
+- 不代办债务协商,不联系债权方,不读取银行卡。
+
+## 8. 隐私与安全摘要
+
+- 不要求真实姓名、手机号、身份证、银行卡或精确住址。
+- 国家由用户选择,不采集城市和实时位置。
+- 精确债务、收入、开销和 AI 对话不进入公开地图。
+- 每笔债务默认仅自己可见;公开时只允许匿名区间。
+- 公开故事会清理联系方式、网址、账号和精确金额,并进入审核。
+- 世界聚合至少达到 30 个不同参与者;MBTI 等可选画像还要求单组至少 5 人。
+- 用户可以导出数据、撤回故事并永久删除账号和角色数据。
+- 不开放陌生人私信、转账、众筹、催收联系或收费服务入口。
+
+## 9. “这不是……”标准说明
+
+上岸星球不是银行、征信机构、贷款平台、投资平台、债务减免公司或专业咨询机构。所有财务数据均为用户自报,目前未连接银行。页面中的利息、现金流和还款路线用于教育性整理,不构成财务、法律、医疗或税务建议,也不保证减债结果。
+
+Debt World is not a bank, credit bureau, lender, investment platform, debt-relief company, or professional advisory service. Financial data is self-reported and no bank is currently connected. Interest estimates, cash-flow views, and repayment routes are educational organization tools, not financial, legal, medical, or tax advice, and they do not guarantee debt reduction.
+
+## 10. Product Hunt 提交字段
+
+- **Name:** Debt World
+- **Tagline:** A walkable anonymous world for real debt journeys
+- **Website:**
+- **Topics:** Personal Finance, Mental Health, Games, AI, Social Impact
+- **Short description:** Organize multiple debts through conversation, watch them become a private game-like character and real-world timeline, and explore reviewed anonymous stories from people around the world.
+
+### Maker first comment
+
+I built Debt World because social media often makes ordinary people feel uniquely behind. The product does not celebrate debt or promise a shortcut out. It gives people a private, visual way to organize multiple debts, income, living costs, interest, due dates, and real repayment updates—then lets them explore carefully reviewed anonymous stories from others.
+
+The current public beta is free. Data is self-reported; no bank is connected. Exact financial data stays private unless a person separately chooses to share an anonymous range, and public stories are moderated. Kian, the AI guide, organizes information and questions but does not act as a financial adviser or lawyer.
+
+I am looking for honest feedback on three things: Does the world reduce isolation? Is the debt setup clear enough? Which privacy boundary still feels uncomfortable?
+
+Please try it and tell me what is confusing or unsafe. Feedback is more useful than praise.
+
+## 11. Show HN 草稿
+
+### Title
+
+Show HN: Debt World – a walkable anonymous world for real debt journeys
+
+### Body
+
+I made Debt World after noticing how strongly social media can create an “everyone else is rich” illusion. Instead of another polished net-worth dashboard, it turns self-reported debts, income, living costs, due dates, interest rates, and real payment updates into an anonymous character inside a small world.
+
+The world is intentionally not a debt leaderboard. Exact amounts remain private. Public stories require separate consent, remove contact details and exact numbers, and are reviewed before appearing. There is no peer-to-peer messaging, lending, or debt-relief sales. The AI guide only turns free-form descriptions into drafts that the user must confirm.
+
+The current build is bilingual Chinese/English, works on desktop and mobile, and can fall back to on-device guidance when the network AI is unavailable. I would especially value feedback on onboarding clarity, the emotional effect of the visual metaphor, and the privacy model.
+
+## 12. FAQ
+
+### 这是债务排行榜吗?
+
+不是。网站不公开“谁欠得最多”,只在达到隐私门槛后展示匿名群体趋势。
+
+### 会不会让我更焦虑?
+
+角色、锁链和金额可能引起不同感受,因此用户可以只保存在本机、退出流程或删除数据。产品目标是把压力拆开,不用恐吓、倒计时或羞辱促使用户还款。
+
+### 数据真实吗?
+
+数据来自用户本人填写和确认,不代表银行或征信记录。公开故事经过隐私清理与审核,但网站无法保证每条自报信息绝对准确。
+
+### 为什么不直接连接银行?
+
+公测阶段优先验证用户价值、隐私和持续更新行为。跨国银行连接昂贵且差异巨大,过早接入会扩大安全和成本风险。
+
+### 免费吗?
+
+公测阶段免费,不推荐贷款、不收取债务金额比例,也不售卖债务减免服务。
+
+### 支持哪些语言?
+
+当前完整支持中文和英文。其他语言会在真实用户和志愿翻译出现后分阶段加入,不宣传为已经支持所有语言。
+
+### 可以删除吗?
+
+可以。用户可以导出个人数据,撤回公开故事,并永久删除账号和角色数据。
+
+### AI 会替我做决定吗?
+
+不会。AI 生成的内容都是草稿或教育性清单,金额、债务和行动由用户本人确认。
+
+## 13. 创始人可用引语
+
+### 中文
+
+“我不想再做一个告诉人们怎样显得更富有的产品。我想做一个地方,让普通人看见真实生活、把压力拆清楚,并知道自己不是唯一一个正在努力的人。”
+
+### English
+
+“I did not want to build another product that teaches people how to look wealthier. I wanted a place where ordinary people can see real life, make pressure legible, and know they are not the only person trying to move forward.”
+
+## 14. 对外表达红线
+
+### 可以说
+
+- 帮助整理、看清、记录和比较不同思路。
+- 匿名、自报、可导出、可删除、经过审核。
+- 减少孤立感,寻找处境相似的经验。
+
+### 不可以说
+
+- “AI 帮你摆脱债务”“保证上岸”“最快还清方案”。
+- “专业财务顾问 + 律师”“替你解决催收”。
+- “全球最大债务数据库”“已有来自所有国家的用户”。
+- 任何尚未验证的用户数量、成功率、节省金额或上岸案例。
diff --git a/launch-kit/PRODUCT_INTRO_SHORT.md b/launch-kit/PRODUCT_INTRO_SHORT.md
new file mode 100644
index 0000000..ccad4e9
--- /dev/null
+++ b/launch-kit/PRODUCT_INTRO_SHORT.md
@@ -0,0 +1,9 @@
+# 上岸星球 / Debt World · 简洁功能介绍
+
+## 中文
+
+上岸星球(Debt World)是一个会随着真实匿名数据不断生长、可以走进去的债务世界。用户先与 AI 小岸对话,整理房贷、信用卡、学贷等多笔债务,以及收入、生活开销、利率、还款日和计划;系统会生成独特角色、债务标签和真实进度。每次确认真实还款后,余额、锁链和世界状态才会变化。用户还可以浏览经过授权和审核的匿名故事、互相送光、分享上岸方法。精确金额默认私密,支持导出和永久删除;网站不连接银行、不销售贷款,也不替代专业财务或法律意见。
+
+## English
+
+Debt World is a shared, walkable world that grows from real anonymous debt patterns without turning debt into shame. Users talk with Kian, the AI guide, to organize multiple debts, income, living costs, interest, due dates, and repayment plans. The product turns that information into a personal character, clear debt labels, and progress that changes only when a real payment is confirmed. People can also explore reviewed anonymous stories and send encouragement. Exact amounts are private by default, data can be exported or permanently deleted, and the site does not connect to banks, sell loans, or replace professional financial or legal advice.
diff --git a/launch-kit/PUBLIC_BETA_CHECKLIST.md b/launch-kit/PUBLIC_BETA_CHECKLIST.md
new file mode 100644
index 0000000..7488077
--- /dev/null
+++ b/launch-kit/PUBLIC_BETA_CHECKLIST.md
@@ -0,0 +1,55 @@
+# 全球公测发布门槛
+
+宣传素材已经就绪,但“能宣传”不等于“可以无限放量”。以下项目完成后,才把文案从“邀请/限量公测”切换为“任何人可以注册”。
+
+## P0:开放注册前必须完成
+
+- [x] 将注册从邀请码模式改为公开注册,同时保留每日 100 人上限和一键暂停。
+- [x] 注册加入 Turnstile;登录与社区写入保留独立频率限制,高风险公开内容继续人工审核。
+- [ ] 验证账号跨设备登录、密码恢复、数据导出与彻底删除;密码绝不进入日志或反馈。
+- [ ] 为数据库、AI 请求、错误率和带宽设置每日告警与预算上限。
+- [ ] 完成手机端、慢网、VPN/网络失败和旧设备测试。
+- [ ] 对中英文隐私说明、社区规则、删除说明和危机提示做人工复核。
+- [ ] 补充网站运营主体、适用条款和目标地区所需的正式法律审阅。
+- [ ] 完成数据库恢复演练,而不仅是数据删除测试。
+- [ ] 确认管理员每天能处理投稿、举报和严重安全反馈。
+- [ ] 准备紧急暂停注册、关闭投稿和回退版本的操作卡。
+
+## P1:100 人前完成
+
+- [ ] 首页明确显示“数据为本人填写、未连接银行”。
+- [ ] 注册完成后立即告诉用户如何导出和删除。
+- [ ] 新用户 10 分钟任务在中文和英文各由 5 名陌生测试者完成。
+- [ ] 建立反馈分类:阻塞、安全、隐私、情绪伤害、翻译、普通体验、功能建议。
+- [ ] 验证匿名聚合门槛不会因为重复账号或小样本泄露个人。
+- [ ] 建立真实上岸状态:最低原始债务、持续时间、多个账期、真实还款记录和最终余额校验。
+
+## P2:Product Hunt / Show HN 前完成
+
+- [x] 无邀请码即可完成账号、角色、进入共享大世界和反馈的完整体验。
+- [ ] 首页 30 秒内说清“为什么存在、能做什么、数据是否公开”。
+- [ ] 准备 30–60 秒无个人数据的产品录屏。
+- [ ] 创始人可以在发布后连续 12 小时回复问题和处理异常。
+- [ ] Product Hunt 只请求访问和评论,不请求 upvote。
+- [ ] Show HN 不请朋友投票,不发布只有注册页的版本。
+
+## P3:GitHub 公开前完成
+
+- [ ] 决定源码是否公开,以及使用何种许可证;没有许可证就不称为开源。
+- [ ] 添加 `LICENSE`、`CODE_OF_CONDUCT.md`、`SECURITY.md` 和 Issue 模板。
+- [ ] 检查提交历史、构建文件和文档中没有密钥、真实用户数据或私有运营信息。
+- [ ] 把可公开代码与部署密钥、管理员配置和私密运营数据彻底分离。
+- [ ] 设置安全漏洞私密报告渠道,不让用户在公开 Issue 中粘贴敏感信息。
+
+## 发布日绿灯指标
+
+- 最近 7 天严重安全事件:0。
+- 删除测试:100% 成功。
+- 关键接口错误率:低于 1%。
+- 管理员审核积压:低于一天处理能力。
+- AI/托管预计日成本:低于设定预算。
+- 一键暂停注册和回退版本:已实际演练。
+
+## 当前结论
+
+分阶段公开测试已经开始:无需邀请码,但每日注册限制为 100 人,并保留 Turnstile、审核、举报和紧急暂停。仍不建议在多个社区同一时间大规模投放;先观察 24–48 小时错误率、审核积压、AI 用量和真实反馈,再逐步扩大。
diff --git a/launch-kit/README.md b/launch-kit/README.md
new file mode 100644
index 0000000..0627a7f
--- /dev/null
+++ b/launch-kit/README.md
@@ -0,0 +1,47 @@
+# 上岸星球全球公测发布包
+
+更新日期:2026-07-30
+
+这套材料用于把上岸星球从邀请内测推进到分阶段公开测试。对外统一使用:
+
+- 中文名:**上岸星球**
+- 英文名:**Debt World**
+- 中文解释:**一个可以行走的匿名债务世界**
+- English descriptor: **A walkable anonymous world for real debt journeys.**
+- 网址:
+
+`Debt Atlas` 仅作为旧视觉稿中的历史名称,不再用于新的公开文案,避免品牌分裂。
+
+## 今晚可以直接使用
+
+1. 产品、媒体、商店与 FAQ 文案:[PRESS_KIT_ZH_EN.md](./PRESS_KIT_ZH_EN.md)
+2. 国内外平台帖子、私信和回复:[SOCIAL_COPY_ZH_EN.md](./SOCIAL_COPY_ZH_EN.md)
+3. 分阶段放量、渠道与 30 天节奏:[CHANNEL_PLAYBOOK.md](./CHANNEL_PLAYBOOK.md)
+4. 未来公开 GitHub 仓库首页草稿:[GITHUB_PUBLIC_README_DRAFT.md](./GITHUB_PUBLIC_README_DRAFT.md)
+5. 公测前必须完成的产品门槛:[PUBLIC_BETA_CHECKLIST.md](./PUBLIC_BETA_CHECKLIST.md)
+6. 原创宣传图生成记录:[IMAGE_PROMPTS.md](./IMAGE_PROMPTS.md)
+
+## 宣传图资产
+
+| 文件 | 尺寸 | 推荐用途 |
+|---|---:|---|
+| `public/og-beta.png` | 宽屏 | 中文首发、文章头图、公开测试主海报 |
+| `launch-kit/images/og-v2.png` | 宽屏 | 功能介绍、AI 整理债务流程 |
+| `launch-kit/images/og.png` | 宽屏 | 全球数据、世界地图主题 |
+| `launch-kit/images/debt-world-global-hero.png` | 1672×941 | 英文官网、Product Hunt、Show HN、媒体报道 |
+| `launch-kit/images/debt-world-public-beta-en.png` | 宽屏 | 可直接发布的英文 PUBLIC BETA 主海报 |
+| `launch-kit/images/debt-world-social-square.png` | 1254×1254 | 小红书、微博、Threads、Instagram、社区帖子 |
+| `launch-kit/images/debt-world-journey-vertical.png` | 972×1619 | 竖版故事、Reels/TikTok 封面、创始人叙事 |
+
+新生成的三张图片均为无文字母版,方便在不同语言中复用。发布时把标题放在平台正文或使用设计工具覆盖,避免图片里的机器翻译和小字错误。
+
+## 公开时永远保留的四句话
+
+- 数据来自用户本人填写,目前没有连接银行。
+- 默认私密;公开故事必须单独授权并经过审核。
+- 小岸提供教育性整理,不是财务顾问、律师、医生或债务减免机构。
+- 这是缓解焦虑和看清现实的工具,不保证任何人成功上岸。
+
+## 当前真实状态
+
+网站已进入分阶段公开测试:账户注册无需邀请码,注册入口保留 Turnstile、每日 100 人上限和一键暂停;公开故事继续单独授权并经过审核。对外统一说“公开测试已开放”,不说“正式成熟产品”或“全球所有地区都已完成合规”。
diff --git a/launch-kit/REDDIT_FOUNDER_STORY_2026-08-03.md b/launch-kit/REDDIT_FOUNDER_STORY_2026-08-03.md
new file mode 100644
index 0000000..e2ef4d8
--- /dev/null
+++ b/launch-kit/REDDIT_FOUNDER_STORY_2026-08-03.md
@@ -0,0 +1,78 @@
+# Reddit founder-story post · 2026-08-03
+
+Status: submitted on 2026-08-03 after the founder confirmed the exact target and copy. Reddit immediately marked it as removed by its automated filters, so it is not currently visible in the community feed. Do not repost or cross-post this copy.
+
+Post URL: https://www.reddit.com/r/SideProject/comments/1ve8hgd/debt_world_a_walkable_anonymous_world_for_real/
+
+## Product purpose summary · 产品初衷总结
+
+上岸星球 / Debt World 的出发点,是对抗社交媒体制造的“别人都很有钱、只有我过得很吃力”的错位感。房贷、信用卡、学贷、医疗、经营和亲友借款等压力通常被隐藏,普通人因此很容易把普遍存在的处境误解成自己的失败。
+
+这个产品把匿名、自报的债务整理和真实还款进度放进一个可以行走、会成长的游戏化世界。它不是比惨或欠款排行榜,也不是贷款、债务减免或专业咨询平台。核心目标是让压力变得可理解、减少孤立感,并帮助用户把混乱的处境拆成下一步能够处理的事实与行动。
+
+## Proposed target
+
+- Community: `r/SideProject`
+- Post type: text post with one founder-disclosed product link
+- Community fit: the community describes itself as a place for sharing side projects and receiving constructive feedback.
+- Title format check: follows `Project name — short description`.
+- Do not cross-post this copy to another community.
+- Do not post to `r/indiehackers` today: its current guidance says new accounts must wait and promotional requests must use the Self Promotion category.
+
+## Exact title
+
+Debt World — A walkable anonymous world for real debt journeys
+
+## Exact body
+
+I’m the founder and builder of Debt World.
+
+The idea came from a mismatch I kept noticing online: social feeds can make ordinary life look unusually wealthy, while mortgages, credit cards, student loans, medical bills, business debt, and money owed to family or friends stay mostly invisible.
+
+When that pressure is hidden, people can mistake a common situation for a personal failure.
+
+I wanted to build the opposite kind of social space.
+
+Debt World turns a self-reported debt journey into a walkable, game-like world. A user can create a private account without an email, phone number, or legal name; choose a country and local currency; describe their situation to Kian; organize multiple debts; and track balances, APRs, due dates, income, essential costs, and repayments.
+
+Only a payment the user confirms as real changes their progress. Exact personal amounts and private AI conversations do not enter the public map.
+
+The hardest product decisions are not technical:
+
+- How do you make debt visual without turning hardship into entertainment?
+- How do you make an anonymous world feel human without exposing people?
+- How do you let aggregate data grow into new districts without publishing free-text stories or small groups?
+- How do you make AI useful for organizing facts without pretending it is a financial adviser or lawyer?
+
+The current public beta is free and bilingual. It is self-reported, does not connect to a bank, currently requires registration, and is not a lender, debt-relief service, or substitute for professional advice.
+
+At this stage, one answer would help me more than a generic review:
+
+**What would make you trust—or immediately distrust—a product that visualizes debt pressure?**
+
+Public beta: https://www.debtworld.org/en?src=redditsideproject
+
+Disclosure: I built it. I’m looking for blunt feedback, especially about privacy, tone, and whether the game-like metaphor feels respectful.
+
+## Proposed image
+
+`launch-kit/daily-social/2026-08-03-repayment-changes-world.png`
+
+The image will be attached only if Reddit's text-post composer supports a single inline image without removing the complete body. Otherwise publish the text post without an image rather than changing post type or dropping context.
+
+## Privacy and claims check
+
+- No real username, debt amount, income, account identity, private AI conversation, or admin data.
+- No fabricated user count, traffic, conversion, testimonial, repayment outcome, or funding claim.
+- No promise that using the product reduces debt or guarantees repayment.
+- Clearly discloses the founder relationship and current beta limitations.
+- Does not ask people to publish personal debt details in Reddit comments.
+- Does not promote loans, debt relief, financial products, direct messages, or transfers.
+- Uses one channel-specific source marker: `redditsideproject`.
+
+## Publication result
+
+- Submitted to `r/SideProject` as a text post; the composer did not provide a usable single-image attachment while preserving the full body, so the authorized text-only fallback was used.
+- The exact title, full founder-disclosed body, privacy boundaries, and `src=redditsideproject` link were verified on the account's submitted-posts page.
+- Reddit displayed: “Sorry, this post was removed by Reddit's filters.” It therefore must not be counted as a public community placement or as successful distribution.
+- No retry, title variation, cross-post, comment promotion, or moderator message was sent.
diff --git a/launch-kit/REDDIT_LAUNCH_KIT.md b/launch-kit/REDDIT_LAUNCH_KIT.md
new file mode 100644
index 0000000..a11067c
--- /dev/null
+++ b/launch-kit/REDDIT_LAUNCH_KIT.md
@@ -0,0 +1,121 @@
+# Debt World · Reddit public-beta launch kit
+
+## Account profile
+
+- Requested username: `rback37`
+- Display name: `Debt World · 上岸星球`
+- About: `Building Debt World — a shared, walkable world for honest debt journeys. Public beta open worldwide.`
+- Website:
+- Avatar: `launch-kit/assets/debt-world-avatar-v1-github.jpg`
+- Registration status: account `rback37` created and signed in; profile completion is the next manual approval step.
+
+## Launch gate
+
+Do not publish the Reddit launch post until all three checks pass on the public site:
+
+1. A new user can register.
+2. The same user can create a character, add at least one debt, and enter the shared world.
+3. The owner dashboard records the new account and signup source without exposing private debt details.
+
+Tracked entry:
+
+## First objective
+
+Recruit 20–50 thoughtful testers, not maximum traffic. Ask for one onboarding problem, one privacy concern, and one reason they would or would not return in seven days.
+
+## Community order
+
+1. Start with a single builder/beta-testing community such as r/SideProject or r/alphaandbetausers. Recheck its current sidebar rules, account-age requirements, karma requirements, required flair, and pinned promotion thread immediately before posting.
+2. Reply to every genuine comment on that one post before using a second community.
+3. For debt-support communities such as r/debtfree or r/povertyfinance, ask moderators first. Do not post the product link unless they approve it.
+4. Do not mass-post the same copy, mass-message members, or place unsolicited promotional comments under personal debt stories.
+5. Do not use r/InternetIsBeautiful from a new project-only account. Its current moderation follows a 90/10 participation rule and also rejects sites that require account information for the full experience.
+6. Do not use r/startups for a direct launch link. Participate there only when the post itself teaches something useful and fully follows its current self-promotion rules.
+
+## New-account warm-up
+
+- Complete the profile, avatar, bio, and website link before participating.
+- Spend the first 5–7 days making 8–12 genuine, non-promotional comments in relevant builder, accessibility, game-design, and privacy discussions.
+- Never manufacture engagement, use alternate accounts, or ask people to upvote.
+- Publish the launch post only after the account has some normal participation and the target community rules have been rechecked on the posting day.
+
+Reddit's current site-wide guidance treats repeated or unsolicited mass engagement as spam, including automated promotion, mass private messages, repetitive cross-community posting, and artificial voting. Promotional content is not automatically spam, but each community may ban it or apply participation-ratio rules. The operating rule for this launch is therefore: one disclosed post in one suitable community, no automated posting, and no second community until the first discussion has been answered and reviewed.
+
+Official references checked 2026-08-01:
+
+-
+-
+
+## Primary Reddit post
+
+**Suggested flair:** Self Promotion / Feedback, only if the community provides it.
+
+**Title**
+
+I built a game-like debt world to counter the “everyone else is rich” feeling — looking for honest privacy and UX feedback
+
+**Body**
+
+I am the maker of Debt World, a free bilingual public beta inspired by a feeling I kept seeing online: ordinary people can feel as if everyone else is wealthy, while mortgages, credit cards, student loans, medical bills, and money owed to friends stay invisible.
+
+Debt World lets a person organize self-reported debts, income, living costs, interest, due dates, and real payment updates around an anonymous character. The character’s labels, burdens, chains, and progress change as the person confirms real updates. Everyone enters one shared world that can grow as new anonymous debt patterns appear. Exact personal amounts remain private on the public map.
+
+It does not connect to banks, sell loans or debt relief, rank individuals by debt, or replace professional advice. Data can be exported or permanently deleted.
+
+I am not asking anyone to disclose their debt in this thread. I would value feedback on three things:
+
+- Which onboarding step feels confusing?
+- What privacy concern would stop you from using it?
+- What would make you return in seven days to update progress?
+
+Public beta:
+
+Disclosure: I built it. The beta is free.
+
+## Moderator permission message for debt-support communities
+
+**Subject:** Permission to share a free, privacy-first debt tracking beta
+
+Hi moderators,
+
+I built a free bilingual web experiment called Debt World. It helps people organize self-reported debts, income, living costs, interest, due dates, and real payment updates around an anonymous game-like character.
+
+It is not a lender, debt-relief service, financial adviser, lead generator, or paid product. Exact amounts remain private by default. Public stories require separate consent, remove contact details and exact figures, and are reviewed before appearing. There is no direct messaging, solicitation, crowdfunding, or loan promotion.
+
+Would one clearly disclosed, feedback-focused post be appropriate in your community? I would not ask members to disclose personal financial details in comments, and I would remove the post if it is not a fit.
+
+Product:
+
+Thank you for considering it.
+
+## Comment response templates
+
+**If someone asks whether it is financial advice**
+
+It is a pressure-mapping and progress-tracking tool, not personalized financial or legal advice. Kian can help organize numbers and questions, but decisions involving contracts, collections, insolvency, or local law should be checked with a qualified professional in the user’s location.
+
+**If someone raises a privacy concern**
+
+That concern is useful. Exact debt data is private by default; a public story requires separate consent and moderation, and users can export or permanently delete their account and character data. Please tell me which screen or sentence failed to make that clear so I can improve it.
+
+**If someone reports a bug**
+
+Thank you. Please share only the page, action, browser/device, and visible error. Do not post a password, bank details, identity document, full statement, or exact private debt amount.
+
+## 48-hour operating plan
+
+- Hour 0: publish one approved post with the tracked link.
+- Hours 0–2: remain available and answer comments personally.
+- Hour 6: record visits, registrations, completed characters, first debts added, and blocking errors.
+- Hour 24: post a transparent comment with what was fixed or learned; do not repost the link elsewhere yet.
+- Hour 48: decide whether to approach a second builder community or send moderator permission requests to debt-support communities.
+
+## Success measures
+
+- Registration completion rate.
+- Account-to-character onboarding completion rate.
+- Percentage of users who add at least one debt.
+- Number of useful feedback reports rather than raw clicks.
+- Seven-day return rate once enough time has passed.
+
+Reddit allows some promotion, but each community sets its own rules. A launch should be a single disclosed feedback request, supported by genuine participation, never automated or repeated unsolicited promotion.
diff --git a/launch-kit/SOCIAL_COPY_ZH_EN.md b/launch-kit/SOCIAL_COPY_ZH_EN.md
new file mode 100644
index 0000000..dcf707f
--- /dev/null
+++ b/launch-kit/SOCIAL_COPY_ZH_EN.md
@@ -0,0 +1,151 @@
+# 上岸星球公测传播文案库
+
+文案分为“创始人故事”和“公开测试上线”两套。当前公开测试已开放,无需邀请码;优先使用上线版,并统一使用独立域名。
+
+## 1. 中文创始人故事(预告版)
+
+我一直觉得,社交网络有一个很伤人的错觉:打开页面,好像每个人都住大房子、开好车、随时旅行,只有普通人的房贷、信用卡、学贷、医疗费和欠朋友的钱被藏了起来。
+
+所以我做了一个可以走进去的“债务世界”——上岸星球。
+
+你可以用匿名小人把自己的每一笔债务、每月收入、生活开销、利息、还款日和计划放到看得见的地方。欠房贷的人可能背着一栋小房子,债务越少,身上的锁链会越少。你也能看到经过授权和审核的普通人故事,给对方送一点光。
+
+它不是贷款平台,不卖理财,不承诺帮任何人快速上岸。所有数据都是本人填写,当前没有连接银行;精确金额默认私密,也可以导出和彻底删除。
+
+第一轮邀请内测效果比我预想得好。现在我正在准备小范围公开测试,希望找到不同国家、不同债务类型、愿意直接指出问题的人。
+
+我最想知道的不是“你觉得好不好看”,而是:它有没有让你更清楚一点?哪个地方让你不舒服?什么会阻止你回来更新真实进度?
+
+## 2. 中文公开测试上线帖
+
+上岸星球公开测试开始了。
+
+这不是一个展示“人均富豪”的地方,而是一个可以行走的匿名债务世界。
+
+你可以:
+
+- 与小岸聊聊,把多笔债务拆清楚;
+- 记录余额、利率、最低还款、收入、开销和真实进度;
+- 让债务变成角色身上的标签、背负物和逐渐减少的锁链;
+- 在地图里找到经过审核的匿名故事,给正在前进的人送一点光;
+- 随时导出或永久删除自己的数据。
+
+网站免费,不连接银行,不推荐贷款,也不提供债务减免服务。AI 只做教育性整理,不替代财务顾问、律师或医生。
+
+体验地址:
+
+如果你愿意测试,请只告诉我三件事:哪里卡住、哪里不信任、什么会让你七天后回来。
+
+## 3. 小红书/短内容创作记录
+
+### 标题备选
+
+- 我做了一个“反人均富豪”的债务世界
+- 如果每个人头顶都能看到真实负债
+- 我把房贷、信用卡和焦虑做成了一个小游戏
+
+### 正文
+
+小红书最容易让我产生的一种错觉是:别人好像都很有钱。
+
+但现实里的普通人,可能同时背着房贷、信用卡、学贷、经营压力,甚至欠朋友的钱。只是这些不会出现在精致的照片里。
+
+我最近做了一个小网页实验:每个人先和一只叫“小岸”的金条狗聊聊,把自己的债务、收入、日常开销和还款计划说清楚,然后生成一个匿名小人。债务会变成小人身上的标签和背负物,真实还款后锁链才会慢慢减少。
+
+它不是比惨,也不做“谁欠最多”的榜单。我更希望它让人发现:压力是真实的,但你并不是唯一一个正在努力的人。
+
+现在刚完成邀请内测,我还在继续改。最难的不是写功能,而是怎样让金额足够真实,又不让人觉得被评判。
+
+注:是否可以附测试地址、二维码或招募信息,以发布当天平台和话题规则为准;不使用“私我领码”、谐音外链或批量评论引流。
+
+## 4. 微博 / Threads 中文短帖
+
+我做了一个“反人均富豪”的小游戏式网页:上岸星球。
+
+每个人用匿名小人记录真实债务、收入、开销和还款进度。债务会变成标签、背负物和锁链;真实还款后,世界才会变化。没有欠款羞辱榜,没有贷款推广,也不保证快速上岸。
+
+我希望它至少能让普通人知道:你不是唯一一个背着压力生活的人。
+
+## 5. English launch post (X / Bluesky / Threads)
+
+Social media can make ordinary people feel as if everyone else is rich.
+
+I built Debt World to reverse that illusion: organize real debts, income, living costs, interest, due dates, and payment updates around an anonymous game-like character—then walk through reviewed stories from people who are moving forward too.
+
+No bank connection. No debt leaderboard. No lending or debt-relief sales. Exact amounts stay private unless you separately choose an anonymous range.
+
+Public beta: https://www.debtworld.org/
+
+I want honest feedback on clarity, emotional impact, and privacy—not compliments.
+
+## 6. English LinkedIn founder post
+
+Most personal finance products begin with dashboards. I began with a feeling: the isolation created by the online illusion that everyone else is doing well.
+
+Debt World is a bilingual, game-like web experiment where a person can organize multiple debts through conversation, see income and living costs together, track real payment updates, and explore moderated anonymous stories from others. Debt changes the character's visible burdens and chains, but the product never turns debt into a score of personal worth.
+
+The difficult part is not drawing a progress bar. It is designing boundaries: exact data private by default, separate consent for public stories, moderation before publication, export and permanent deletion, no peer-to-peer lending, and no AI pretending to be a financial adviser or lawyer.
+
+We are preparing a staged public beta and looking for early users across countries, debt types, devices, and levels of financial confidence. If you try it, I would value the uncomfortable feedback most: what feels unclear, judgmental, or unsafe?
+
+## 7. Reddit 版主申请(先发给版主)
+
+Subject: Permission to share a free, privacy-first debt tracking beta
+
+Hi moderators,
+
+I built a free bilingual web experiment called Debt World. It lets people organize self-reported debts, income, living costs, interest, due dates, and real payment updates around an anonymous game-like character. It is not a lender, debt-relief service, financial adviser, lead generator, or paid product.
+
+Exact amounts remain private by default. Public stories require separate consent, remove contact details and exact numbers, and are reviewed before appearing. There is no direct messaging, solicitation, crowdfunding, or loan promotion.
+
+Would a single feedback-focused post be appropriate here? I would disclose that I am the maker, avoid collecting personal financial details in comments, and remove the post if it is not a fit. I will not mass-message members or repost repeatedly.
+
+Product: https://www.debtworld.org/
+
+Thank you for considering it.
+
+## 8. Reddit 社区帖子(仅获得许可后)
+
+Title: I built a game-like debt world to counter the “everyone else is rich” feeling—looking for privacy and UX feedback
+
+I am the maker of Debt World, a free bilingual web beta. It turns self-reported debts, income, living costs, interest, due dates, and real payment updates into a private character and timeline. Reviewed anonymous stories can appear in the world, but exact amounts stay private and there is no individual debt leaderboard.
+
+It does not connect to banks, sell debt relief, recommend loans, or replace professional advice. The AI guide only organizes drafts that the user must confirm.
+
+I am not asking anyone to post their debt amount here. I would value feedback on the onboarding, emotional effect, and privacy model. What would make a tool like this feel helpful instead of judgmental?
+
+Link: https://www.debtworld.org/
+
+Disclosure: I built it; the beta is free.
+
+## 9. Discord / Slack / 小群邀请
+
+I’m opening a small public-beta batch for Debt World, a free anonymous, game-like way to organize multiple debts and real repayment progress. It is bilingual Chinese/English, does not connect to a bank, and does not sell loans or debt-relief services.
+
+I am looking for people willing to test for 10 minutes and report one confusing step and one privacy concern. No one needs to reveal an exact debt amount publicly.
+
+Try it: https://www.debtworld.org/
+
+## 10. 私信邀请(中文)
+
+我在做一个叫“上岸星球”的匿名网页实验,把债务、收入、生活开销和真实还款进度变成可以行走的小人世界。它不收费、不连接银行,也不做贷款或债务减免服务。
+
+如果这个记录需求刚好与你有关,我想邀请你用 10 分钟试一下。你不需要告诉我具体欠款,也不用公开任何内容;只要告诉我哪一步看不懂、哪项最不愿意填、哪里让你不信任。
+
+## 11. 反馈追问模板
+
+### 用户说“挺好的”
+
+谢谢,但我现在最需要的是具体问题。你能告诉我:在哪一步停顿最久?哪一项数据你最不愿意填写?如果七天后不回来,最可能是什么原因?
+
+### 用户担心隐私
+
+这个担心合理。精确金额默认不进入公开世界,公开故事要单独授权并经过审核;你也可以只保存在本机,或导出后永久删除。请告诉我是哪句话或哪个开关没有让这件事足够清楚,我会优先修改。
+
+### 用户要求财务/法律结论
+
+小岸可以帮你整理金额、利率、账单和要问的问题,但不能替持牌财务顾问或律师下结论。涉及合同费用、催收、诉讼期限或当地法律时,请向所在地的正规机构或专业人士核实。
+
+### 用户遇到严重故障
+
+先不要继续录入。请只发送发生问题的页面、操作步骤、设备/浏览器和错误提示截图,不要发送密码、身份证、银行卡、精确债务或完整账单。我会把它按阻塞/安全问题优先处理。
diff --git a/launch-kit/X_LAUNCH_KIT.md b/launch-kit/X_LAUNCH_KIT.md
new file mode 100644
index 0000000..d30f7e1
--- /dev/null
+++ b/launch-kit/X_LAUNCH_KIT.md
@@ -0,0 +1,139 @@
+# Debt World / 上岸星球:X 公测启动包
+
+更新:2026-08-01
+正式入口:`https://www.debtworld.org/en?src=x`
+
+## 1. 账号资料
+
+- 用户名候选顺序:`@debtworldorg` → `@DebtWorldOrg` → `@DebtWorldApp`
+- 显示名称:`Debt World · 上岸星球`
+- 简介:`A walkable world for real debt journeys—not another highlight reel. Anonymous, privacy-first public beta. Not financial or legal advice. 中文/EN.`
+- 地区:`Global · 全球`
+- 官网:`https://www.debtworld.org/en?src=x`
+- 头像:`launch-kit/assets/debt-world-avatar-v1.png`
+- 首选横幅:`launch-kit/images/debt-world-global-hero.png`(上传时居中裁切)
+- 备用横幅:`launch-kit/images/debt-world-public-beta-en.png`
+
+账号必须由创始人本人完成邮箱/手机号、密码和验证码;不要把登录凭据发到聊天或写入仓库。
+
+## 2. 置顶首发
+
+Most feeds show highlight reels. Debt World shows the weight people quietly carry—and the real steps they take toward shore.
+
+🌍 Walkable anonymous debt world
+🧭 Real repayment progress with Kian
+✦ Privacy-first public beta
+
+Try it: https://www.debtworld.org/en?src=x
+
+## 3. 首周每日内容
+
+### Day 1 — Why this exists
+
+Social feeds can make ordinary people feel uniquely behind.
+
+Debt World builds the opposite: an anonymous world where characters carry real debt types, due dates and progress—without turning private pain into a spectacle.
+
+Public beta: https://www.debtworld.org/en?src=x
+
+### Day 2 — Product mechanic
+
+Debt World’s progress does not move because a game timer says so.
+
+It changes when you record real life: a payment, a verified new balance, a prepayment or real extra income.
+
+The character changes with the journey. The debt itself is never gamified away.
+
+### Day 3 — A useful debt check-in
+
+A 5-minute debt check-in:
+
+1. Use the latest balance—not the original amount.
+2. Record APR and minimum payment separately.
+3. Protect essential living costs.
+4. Choose one action before the next due date.
+
+Kian helps create that clarity. Educational support only.
+
+### Day 4 — Privacy boundary
+
+What Debt World does not ask for:
+
+• legal name
+• email address
+• bank connection
+• public exact income or debt
+
+Private records stay private by default. The shared world grows from limited, anonymous patterns—not personal financial dossiers.
+
+### Day 5 — Build in public question
+
+If a global debt world grew new districts from user-described debt types, what should appear first?
+
+Mortgage Mountain? Medical Debt Harbor? Family & Friends Alley? Tax Hill—or something we have not named?
+
+Real language shapes the taxonomy; humans review it before release.
+
+### Day 6 — Invitation loop
+
+Debt World has personal invite links—but empty signups earn nothing.
+
+A referral activates only after a real person joins and adds at least one debt. Both receive virtual starlight; real balances and credit never change.
+
+Designed for genuine invitations, not growth spam.
+
+### Day 7 — Founder reflection
+
+Building a debt product taught me it cannot be only a tracker. People also need:
+
+• a calm way to name pressure
+• proof they are not uniquely failing
+• one small next action
+• privacy they understand
+
+That is the standard I’m trying to hold with Debt World.
+
+## 4. 内容轮换规则
+
+每天只发布一条主内容,按以下栏目轮换,避免重复链接与近似文案:
+
+1. 产品机制演示;
+2. 非个性化的债务整理知识;
+3. 公开开发记录;
+4. 匿名聚合数据(达到隐私门槛后才发布);
+5. 用户研究问题;
+6. 隐私和安全解释;
+7. 创始人周复盘。
+
+链接不必每天出现。没有新信息时不追热门话题,不堆无关标签,不复制粘贴同一条内容。
+
+## 5. 互动边界
+
+- 可以:回复主动提问、说明产品边界、感谢具体反馈、分享与话题直接相关的非个性化整理方法。
+- 不可以:在陌生人的债务求助下贴推广链接;关键词搜索后批量回复;自动私信;批量关注/取关;购买粉丝;让多个账号互相刷互动。
+- 不公开:用户精确债务、收入、私人 AI 对话、账号信息或可以反推出身份的小样本统计。
+- 涉及自伤、催收威胁、诉讼、破产、跨境税务等高风险情况时,只提供求助方向与当地专业资源提示,不给确定性结论。
+
+## 6. 每日质量检查
+
+- 这条内容是否提供了独立价值,而不只是一个链接?
+- 是否与最近 7 条明显不同?
+- 是否避免“人人都负债”“保证上岸”等无法证明的承诺?
+- 是否没有暴露个人财务信息?
+- 是否写明必要的教育性边界?
+- 链接是否使用 `?src=x`,方便管理员后台查看转化?
+
+## 7. 运营指标(首月)
+
+只看真实质量,不追逐虚假曝光:
+
+- 每日独立访客;
+- X 来源注册数;
+- 注册后首次录债务的比例;
+- 主动反馈数;
+- 7 日回访;
+- 有实质内容的公开回复数量。
+
+## 8. X 规则依据
+
+执行时遵守 X 的真实性和自动化规则:不重复或近重复发帖、不自动追热点、不对关键词搜索结果批量回复、不自动点赞、不批量关注、不发送未经请求的自动私信。当前自动任务只生成草稿,不代替创始人发帖。
diff --git a/launch-kit/assets/debt-world-avatar-v1-github.jpg b/launch-kit/assets/debt-world-avatar-v1-github.jpg
new file mode 100644
index 0000000..8c4d4f2
Binary files /dev/null and b/launch-kit/assets/debt-world-avatar-v1-github.jpg differ
diff --git a/launch-kit/assets/debt-world-avatar-v1.png b/launch-kit/assets/debt-world-avatar-v1.png
new file mode 100644
index 0000000..4df1abf
Binary files /dev/null and b/launch-kit/assets/debt-world-avatar-v1.png differ
diff --git a/launch-kit/daily-social/2026-08-01-shared-world.png b/launch-kit/daily-social/2026-08-01-shared-world.png
new file mode 100644
index 0000000..428b6b8
Binary files /dev/null and b/launch-kit/daily-social/2026-08-01-shared-world.png differ
diff --git a/launch-kit/daily-social/2026-08-02-multi-debt-cashflow.png b/launch-kit/daily-social/2026-08-02-multi-debt-cashflow.png
new file mode 100644
index 0000000..f54cfac
Binary files /dev/null and b/launch-kit/daily-social/2026-08-02-multi-debt-cashflow.png differ
diff --git a/launch-kit/daily-social/2026-08-03-repayment-changes-world.png b/launch-kit/daily-social/2026-08-03-repayment-changes-world.png
new file mode 100644
index 0000000..c1edec8
Binary files /dev/null and b/launch-kit/daily-social/2026-08-03-repayment-changes-world.png differ
diff --git a/launch-kit/daily-social/2026-08-04-feature.png b/launch-kit/daily-social/2026-08-04-feature.png
new file mode 100644
index 0000000..2f4743d
Binary files /dev/null and b/launch-kit/daily-social/2026-08-04-feature.png differ
diff --git a/launch-kit/demo-gif/README_INSERT.md b/launch-kit/demo-gif/README_INSERT.md
new file mode 100644
index 0000000..32c3baa
--- /dev/null
+++ b/launch-kit/demo-gif/README_INSERT.md
@@ -0,0 +1,9 @@
+## Walk the world in 23 seconds · 23 秒看懂上岸星球
+
+
+
+> Actual product capture. Every visible walker uses system demo data. No real user debt, income, account identity, or private AI conversation is shown.
+>
+> 真实产品画面。所有可见角色均为系统演示数据,不展示真实用户的债务、收入、账户身份或私人 AI 对话。
+
+[Enter the public beta](https://www.debtworld.org/en?src=github) · [进入公开测试](https://www.debtworld.org/?src=github)
diff --git a/launch-kit/demo-gif/debt-world-walkthrough-contact-sheet.jpg b/launch-kit/demo-gif/debt-world-walkthrough-contact-sheet.jpg
new file mode 100644
index 0000000..6a5a4fb
Binary files /dev/null and b/launch-kit/demo-gif/debt-world-walkthrough-contact-sheet.jpg differ
diff --git a/launch-kit/demo-gif/debt-world-walkthrough-preview.png b/launch-kit/demo-gif/debt-world-walkthrough-preview.png
new file mode 100644
index 0000000..4291565
Binary files /dev/null and b/launch-kit/demo-gif/debt-world-walkthrough-preview.png differ
diff --git a/launch-kit/demo-gif/debt-world-walkthrough.gif b/launch-kit/demo-gif/debt-world-walkthrough.gif
new file mode 100644
index 0000000..3aba315
Binary files /dev/null and b/launch-kit/demo-gif/debt-world-walkthrough.gif differ
diff --git a/launch-kit/images/debt-world-global-hero.png b/launch-kit/images/debt-world-global-hero.png
new file mode 100644
index 0000000..e0883aa
Binary files /dev/null and b/launch-kit/images/debt-world-global-hero.png differ
diff --git a/launch-kit/images/debt-world-journey-vertical.png b/launch-kit/images/debt-world-journey-vertical.png
new file mode 100644
index 0000000..6b62050
Binary files /dev/null and b/launch-kit/images/debt-world-journey-vertical.png differ
diff --git a/launch-kit/images/debt-world-public-beta-en.png b/launch-kit/images/debt-world-public-beta-en.png
new file mode 100644
index 0000000..abe8e74
Binary files /dev/null and b/launch-kit/images/debt-world-public-beta-en.png differ
diff --git a/launch-kit/images/debt-world-social-square.png b/launch-kit/images/debt-world-social-square.png
new file mode 100644
index 0000000..a4dc190
Binary files /dev/null and b/launch-kit/images/debt-world-social-square.png differ
diff --git a/launch-kit/images/og-v2.png b/launch-kit/images/og-v2.png
new file mode 100644
index 0000000..ef3f6e9
Binary files /dev/null and b/launch-kit/images/og-v2.png differ
diff --git a/launch-kit/images/og.png b/launch-kit/images/og.png
new file mode 100644
index 0000000..f1d3cc7
Binary files /dev/null and b/launch-kit/images/og.png differ
diff --git a/lib/account-server.ts b/lib/account-server.ts
new file mode 100644
index 0000000..9d8d879
--- /dev/null
+++ b/lib/account-server.ts
@@ -0,0 +1,386 @@
+import { env } from "cloudflare:workers";
+import { getD1 } from "@/db";
+import { HttpError, cleanText } from "@/lib/vault-server";
+
+export const ACCOUNT_SESSION_COOKIE = "dw_account";
+const SESSION_DAYS = 30;
+const MAX_PASSWORD_ITERATIONS = 100_000;
+const DEFAULT_PASSWORD_ITERATIONS = MAX_PASSWORD_ITERATIONS;
+const RESERVED_USERNAMES = new Set([
+ "admin",
+ "administrator",
+ "root",
+ "official",
+ "support",
+ "debtworld",
+ "debt-world",
+ "上岸星球",
+]);
+const SIGNUP_SOURCES = new Set(["direct", "github", "xiaohongshu", "weibo", "reddit", "x", "producthunt", "showhn", "friend", "referral", "other"]);
+let accountStorageSchemaPromise: Promise | null = null;
+
+export type AccountRow = {
+ id: string;
+ user_code: string;
+ username: string;
+ username_normalized: string;
+ status: string;
+ created_at: string;
+ last_login_at: string | null;
+ last_seen_at: string | null;
+};
+
+type PasswordAccountRow = AccountRow & {
+ password_hash: string;
+ password_salt: string;
+ password_iterations: number;
+};
+
+function bytesToHex(bytes: Uint8Array) {
+ return Array.from(bytes, (byte) => byte.toString(16).padStart(2, "0")).join("");
+}
+
+function hexToBytes(value: string) {
+ if (!/^[a-f0-9]+$/i.test(value) || value.length % 2) return new Uint8Array();
+ return new Uint8Array(value.match(/.{2}/g)!.map((part) => Number.parseInt(part, 16)));
+}
+
+function randomHex(byteLength: number) {
+ return bytesToHex(crypto.getRandomValues(new Uint8Array(byteLength)));
+}
+
+export async function sha256Hex(value: string) {
+ const digest = await crypto.subtle.digest("SHA-256", new TextEncoder().encode(value));
+ return bytesToHex(new Uint8Array(digest));
+}
+
+function readCookie(request: Request, name: string) {
+ const source = request.headers.get("Cookie") ?? "";
+ for (const part of source.split(";")) {
+ const [key, ...rest] = part.trim().split("=");
+ if (key === name) return decodeURIComponent(rest.join("="));
+ }
+ return "";
+}
+
+export function accountSessionToken(request: Request) {
+ const token = readCookie(request, ACCOUNT_SESSION_COOKIE);
+ return /^[a-f0-9]{64}$/i.test(token) ? token.toLowerCase() : "";
+}
+
+export function normalizeUsername(value: unknown) {
+ const display = cleanText(value, 30).normalize("NFKC");
+ const normalized = display.toLocaleLowerCase("und");
+ if (display.length < 3 || !/^[\p{L}\p{N}][\p{L}\p{N}._-]{2,29}$/u.test(display)) {
+ throw new HttpError(400, "Username must be 3–30 letters or numbers; dots, underscores, and hyphens are allowed after the first character.");
+ }
+ if (RESERVED_USERNAMES.has(normalized)) {
+ throw new HttpError(400, "That username is reserved. Choose another one.");
+ }
+ return { display, normalized };
+}
+
+function validatePassword(value: unknown) {
+ if (typeof value !== "string" || value.length < 10 || value.length > 128) {
+ throw new HttpError(400, "Password must contain 10–128 characters.");
+ }
+ if (!/[\p{L}]/u.test(value) || !/[\p{N}]/u.test(value)) {
+ throw new HttpError(400, "Password must include at least one letter and one number.");
+ }
+ return value;
+}
+
+function passwordIterations() {
+ const workerEnv = env as unknown as Record;
+ const configured = Number(workerEnv.ACCOUNT_PASSWORD_ITERATIONS ?? DEFAULT_PASSWORD_ITERATIONS);
+ return Number.isInteger(configured) && configured >= 1_000
+ ? Math.min(configured, MAX_PASSWORD_ITERATIONS)
+ : DEFAULT_PASSWORD_ITERATIONS;
+}
+
+async function derivePassword(password: string, saltHex: string, iterations: number) {
+ const key = await crypto.subtle.importKey("raw", new TextEncoder().encode(password), "PBKDF2", false, ["deriveBits"]);
+ const bits = await crypto.subtle.deriveBits(
+ { name: "PBKDF2", hash: "SHA-256", salt: hexToBytes(saltHex), iterations },
+ key,
+ 256,
+ );
+ return bytesToHex(new Uint8Array(bits));
+}
+
+function constantTimeEqual(left: string, right: string) {
+ if (left.length !== right.length) return false;
+ let difference = 0;
+ for (let index = 0; index < left.length; index += 1) {
+ difference |= left.charCodeAt(index) ^ right.charCodeAt(index);
+ }
+ return difference === 0;
+}
+
+async function consumeAuthLimit(request: Request, action: "register" | "login", normalizedUsername: string) {
+ const now = new Date();
+ const windowKey = action === "register"
+ ? now.toISOString().slice(0, 10)
+ : `${now.toISOString().slice(0, 13)}:${String(Math.floor(now.getUTCMinutes() / 15) * 15).padStart(2, "0")}`;
+ const ip = cleanText(request.headers.get("cf-connecting-ip") ?? request.headers.get("x-forwarded-for")?.split(",")[0], 80, "unknown");
+ const limitSubject = action === "register" ? "new-account" : normalizedUsername;
+ const limitKey = await sha256Hex(`${action}:${windowKey}:${ip}:${limitSubject}`);
+ const maxAttempts = action === "register" ? 8 : 12;
+ const db = getD1();
+ await db.prepare(
+ `INSERT OR IGNORE INTO account_auth_limits (limit_key, action, window_key, attempts)
+ VALUES (?1, ?2, ?3, 0)`,
+ ).bind(limitKey, action, windowKey).run();
+ const updated = await db.prepare(
+ `UPDATE account_auth_limits SET attempts = attempts + 1, updated_at = CURRENT_TIMESTAMP
+ WHERE limit_key = ?1 AND attempts < ?2`,
+ ).bind(limitKey, maxAttempts).run();
+ if (Number(updated.meta?.changes ?? 0) < 1) {
+ throw new HttpError(429, "Too many attempts. Please wait before trying again.");
+ }
+}
+
+function newUserCode() {
+ return `SHORE-${randomHex(5).toUpperCase()}`;
+}
+
+export function normalizeSignupSource(value: unknown) {
+ const source = cleanText(value, 24).toLowerCase().replace(/[^a-z]/g, "");
+ return SIGNUP_SOURCES.has(source) ? source : source ? "other" : "direct";
+}
+
+async function addMissingColumn(table: string, column: string, definition: string) {
+ const db = getD1();
+ const columns = await db.prepare(`PRAGMA table_info(${table})`).all<{ name: string }>();
+ if (columns.results.some((item) => item.name === column)) return;
+ try {
+ await db.prepare(`ALTER TABLE ${table} ADD COLUMN ${column} ${definition}`).run();
+ } catch (error) {
+ const message = error instanceof Error ? error.message : String(error);
+ if (!/duplicate column/i.test(message)) throw error;
+ }
+}
+
+export async function ensureAccountStorageSchema() {
+ if (!accountStorageSchemaPromise) {
+ accountStorageSchemaPromise = (async () => {
+ const db = getD1();
+ await db.batch([
+ db.prepare(`CREATE TABLE IF NOT EXISTS accounts (
+ id TEXT PRIMARY KEY NOT NULL,
+ user_code TEXT NOT NULL UNIQUE,
+ username TEXT NOT NULL,
+ username_normalized TEXT NOT NULL UNIQUE,
+ password_hash TEXT NOT NULL,
+ password_salt TEXT NOT NULL,
+ password_iterations INTEGER NOT NULL,
+ status TEXT NOT NULL DEFAULT 'active',
+ signup_source TEXT NOT NULL DEFAULT 'direct',
+ created_at TEXT NOT NULL DEFAULT CURRENT_TIMESTAMP,
+ updated_at TEXT NOT NULL DEFAULT CURRENT_TIMESTAMP,
+ last_login_at TEXT,
+ last_seen_at TEXT
+ )`),
+ db.prepare(`CREATE TABLE IF NOT EXISTS account_auth_limits (
+ limit_key TEXT PRIMARY KEY NOT NULL,
+ action TEXT NOT NULL,
+ window_key TEXT NOT NULL,
+ attempts INTEGER NOT NULL DEFAULT 0,
+ updated_at TEXT NOT NULL DEFAULT CURRENT_TIMESTAMP
+ )`),
+ db.prepare(`CREATE TABLE IF NOT EXISTS account_sessions (
+ id TEXT PRIMARY KEY NOT NULL,
+ account_id TEXT NOT NULL REFERENCES accounts(id) ON DELETE CASCADE,
+ token_hash TEXT NOT NULL UNIQUE,
+ expires_at TEXT NOT NULL,
+ created_at TEXT NOT NULL DEFAULT CURRENT_TIMESTAMP,
+ last_seen_at TEXT NOT NULL DEFAULT CURRENT_TIMESTAMP
+ )`),
+ db.prepare(`CREATE TABLE IF NOT EXISTS account_vaults (
+ account_id TEXT PRIMARY KEY NOT NULL REFERENCES accounts(id) ON DELETE CASCADE,
+ vault_id TEXT NOT NULL UNIQUE REFERENCES vaults(id) ON DELETE CASCADE,
+ linked_at TEXT NOT NULL DEFAULT CURRENT_TIMESTAMP
+ )`),
+ ]);
+
+ await addMissingColumn("accounts", "status", "TEXT NOT NULL DEFAULT 'active'");
+ await addMissingColumn("accounts", "signup_source", "TEXT NOT NULL DEFAULT 'direct'");
+ await addMissingColumn("accounts", "updated_at", "TEXT NOT NULL DEFAULT '1970-01-01 00:00:00'");
+ await addMissingColumn("accounts", "last_login_at", "TEXT");
+ await addMissingColumn("accounts", "last_seen_at", "TEXT");
+ await addMissingColumn("account_auth_limits", "updated_at", "TEXT NOT NULL DEFAULT '1970-01-01 00:00:00'");
+ await addMissingColumn("account_sessions", "created_at", "TEXT NOT NULL DEFAULT '1970-01-01 00:00:00'");
+ await addMissingColumn("account_sessions", "last_seen_at", "TEXT NOT NULL DEFAULT '1970-01-01 00:00:00'");
+ await addMissingColumn("account_vaults", "linked_at", "TEXT NOT NULL DEFAULT '1970-01-01 00:00:00'");
+
+ await db.batch([
+ db.prepare("CREATE INDEX IF NOT EXISTS accounts_created_idx ON accounts(created_at)"),
+ db.prepare("CREATE INDEX IF NOT EXISTS account_auth_limits_window_idx ON account_auth_limits(window_key)"),
+ db.prepare("CREATE INDEX IF NOT EXISTS account_sessions_account_idx ON account_sessions(account_id)"),
+ db.prepare("CREATE INDEX IF NOT EXISTS account_sessions_expires_idx ON account_sessions(expires_at)"),
+ db.prepare("CREATE INDEX IF NOT EXISTS account_vaults_vault_idx ON account_vaults(vault_id)"),
+ ]);
+ })().catch((error) => {
+ accountStorageSchemaPromise = null;
+ throw error;
+ });
+ }
+ return accountStorageSchemaPromise;
+}
+
+export async function ensureAccountSignupSourceSchema() {
+ return ensureAccountStorageSchema();
+}
+
+async function createSession(accountId: string) {
+ const rawToken = randomHex(32);
+ const tokenHash = await sha256Hex(rawToken);
+ const expiresAt = new Date(Date.now() + SESSION_DAYS * 86_400_000).toISOString();
+ await getD1().prepare(
+ `INSERT INTO account_sessions (id, account_id, token_hash, expires_at)
+ VALUES (?1, ?2, ?3, ?4)`,
+ ).bind(crypto.randomUUID(), accountId, tokenHash, expiresAt).run();
+ return rawToken;
+}
+
+export function withAccountSession(response: Response, request: Request, rawToken: string) {
+ const secure = new URL(request.url).protocol === "https:" ? "; Secure" : "";
+ response.headers.append(
+ "Set-Cookie",
+ `${ACCOUNT_SESSION_COOKIE}=${rawToken}; Path=/; HttpOnly; SameSite=Lax; Max-Age=${SESSION_DAYS * 86_400}${secure}`,
+ );
+ return response;
+}
+
+export async function clearAccountSession(response: Response, request: Request) {
+ const rawToken = accountSessionToken(request);
+ if (rawToken) {
+ await getD1().prepare("DELETE FROM account_sessions WHERE token_hash = ?1").bind(await sha256Hex(rawToken)).run();
+ }
+ const secure = new URL(request.url).protocol === "https:" ? "; Secure" : "";
+ response.headers.append(
+ "Set-Cookie",
+ `${ACCOUNT_SESSION_COOKIE}=; Path=/; HttpOnly; SameSite=Lax; Max-Age=0${secure}`,
+ );
+ return response;
+}
+
+export async function getAccount(request: Request) {
+ const rawToken = accountSessionToken(request);
+ if (!rawToken) return null;
+ const tokenHash = await sha256Hex(rawToken);
+ const account = await getD1().prepare(
+ `SELECT a.id, a.user_code, a.username, a.username_normalized, a.status,
+ a.created_at, a.last_login_at, a.last_seen_at
+ FROM account_sessions s
+ JOIN accounts a ON a.id = s.account_id
+ WHERE s.token_hash = ?1 AND datetime(s.expires_at) > datetime('now') AND a.status = 'active'
+ LIMIT 1`,
+ ).bind(tokenHash).first();
+ if (!account) return null;
+ await getD1().batch([
+ getD1().prepare(
+ `UPDATE account_sessions SET last_seen_at = CURRENT_TIMESTAMP
+ WHERE token_hash = ?1 AND last_seen_at < datetime('now', '-10 minutes')`,
+ ).bind(tokenHash),
+ getD1().prepare(
+ `UPDATE accounts SET last_seen_at = CURRENT_TIMESTAMP
+ WHERE id = ?1 AND (last_seen_at IS NULL OR last_seen_at < datetime('now', '-10 minutes'))`,
+ ).bind(account.id),
+ ]);
+ return account;
+}
+
+export async function requireAccount(request: Request) {
+ const account = await getAccount(request);
+ if (!account) throw new HttpError(401, "Sign in to continue.");
+ return account;
+}
+
+export async function accountHasVault(accountId: string) {
+ const link = await getD1().prepare(
+ "SELECT vault_id FROM account_vaults WHERE account_id = ?1 LIMIT 1",
+ ).bind(accountId).first<{ vault_id: string }>();
+ return Boolean(link?.vault_id);
+}
+
+export async function registerAccount(request: Request, usernameValue: unknown, passwordValue: unknown, signupSourceValue?: unknown) {
+ let stage = "validation";
+ try {
+ const username = normalizeUsername(usernameValue);
+ const password = validatePassword(passwordValue);
+ const signupSource = normalizeSignupSource(signupSourceValue);
+ stage = "storage_schema";
+ await ensureAccountStorageSchema();
+ stage = "rate_limit";
+ await consumeAuthLimit(request, "register", username.normalized);
+ const db = getD1();
+ stage = "username_check";
+ const existing = await db.prepare(
+ "SELECT id FROM accounts WHERE username_normalized = ?1 LIMIT 1",
+ ).bind(username.normalized).first<{ id: string }>();
+ if (existing) throw new HttpError(409, "That username is already in use.");
+ const salt = randomHex(16);
+ const iterations = passwordIterations();
+ stage = "password_hash";
+ const passwordHash = await derivePassword(password, salt, iterations);
+ const id = crypto.randomUUID();
+ stage = "account_insert";
+ await db.prepare(
+ `INSERT INTO accounts
+ (id, user_code, username, username_normalized, password_hash, password_salt, password_iterations,
+ signup_source, last_login_at, last_seen_at)
+ VALUES (?1, ?2, ?3, ?4, ?5, ?6, ?7, ?8, CURRENT_TIMESTAMP, CURRENT_TIMESTAMP)`,
+ ).bind(id, newUserCode(), username.display, username.normalized, passwordHash, salt, iterations, signupSource).run();
+ stage = "account_readback";
+ const account = await db.prepare(
+ `SELECT id, user_code, username, username_normalized, status, created_at, last_login_at, last_seen_at
+ FROM accounts WHERE id = ?1`,
+ ).bind(id).first();
+ if (!account) throw new Error("Account registration did not return a record.");
+ stage = "session_create";
+ return { account, rawToken: await createSession(id) };
+ } catch (error) {
+ if (error instanceof Error && /unique/i.test(error.message)) {
+ throw new HttpError(409, "That username is already in use.");
+ }
+ if (!(error instanceof HttpError)) {
+ const message = error instanceof Error ? error.message.slice(0, 300) : "Unknown account storage failure";
+ console.error("Debt World account registration failed", { stage, message });
+ }
+ throw error;
+ }
+}
+
+export async function loginAccount(request: Request, usernameValue: unknown, passwordValue: unknown) {
+ const username = normalizeUsername(usernameValue);
+ const password = validatePassword(passwordValue);
+ await ensureAccountStorageSchema();
+ await consumeAuthLimit(request, "login", username.normalized);
+ const db = getD1();
+ const account = await db.prepare(
+ `SELECT id, user_code, username, username_normalized, password_hash, password_salt, password_iterations,
+ status, created_at, last_login_at, last_seen_at
+ FROM accounts WHERE username_normalized = ?1 LIMIT 1`,
+ ).bind(username.normalized).first();
+ if (!account || account.status !== "active") {
+ throw new HttpError(401, "Username or password is incorrect.");
+ }
+ const candidate = await derivePassword(password, account.password_salt, account.password_iterations);
+ if (!constantTimeEqual(candidate, account.password_hash)) {
+ throw new HttpError(401, "Username or password is incorrect.");
+ }
+ await db.prepare(
+ "UPDATE accounts SET last_login_at = CURRENT_TIMESTAMP, last_seen_at = CURRENT_TIMESTAMP WHERE id = ?1",
+ ).bind(account.id).run();
+ return { account, rawToken: await createSession(account.id) };
+}
+
+export function publicAccount(account: AccountRow, vaultLinked: boolean) {
+ return {
+ userCode: account.user_code,
+ username: account.username,
+ createdAt: account.created_at,
+ vaultLinked,
+ };
+}
diff --git a/lib/advisor-server.ts b/lib/advisor-server.ts
new file mode 100644
index 0000000..a42079b
--- /dev/null
+++ b/lib/advisor-server.ts
@@ -0,0 +1,703 @@
+import { env } from "cloudflare:workers";
+import { getD1 } from "@/db";
+import type { AdvisorDebtDraft, AdvisorResult, DebtKind, Locale } from "@/lib/debt-world-types";
+import { HttpError, cleanText, type VaultRow } from "@/lib/vault-server";
+
+export const ADVISOR_MODEL = "gpt-5.6-terra";
+export const MINIMAX_ADVISOR_MODEL = "MiniMax-M2.7";
+export const ADVISOR_DAILY_REQUEST_LIMIT = 20;
+const ADVISOR_DAILY_INPUT_LIMIT = 50_000;
+const ADVISOR_DAILY_OUTPUT_LIMIT = 20_000;
+
+type AdvisorProvider = "openai" | "minimax";
+
+type AdvisorProviderConfig = {
+ provider: AdvisorProvider;
+ model: string;
+ apiKey: string;
+};
+
+const debtKinds = new Set([
+ "mortgage",
+ "card",
+ "education",
+ "medical",
+ "car",
+ "personal",
+ "business",
+ "bnpl",
+ "informal",
+ "other",
+]);
+
+const missingFields = new Set([
+ "kind",
+ "customLabel",
+ "currency",
+ "original",
+ "balance",
+ "monthly",
+ "apr",
+ "minimumPayment",
+ "paymentStatus",
+ "remainingMonths",
+ "dueDay",
+ "method",
+]);
+
+const responseSchema = {
+ type: "object",
+ additionalProperties: false,
+ required: ["reply", "mode", "nextQuestion", "risk", "actions", "drafts"],
+ properties: {
+ reply: { type: "string", minLength: 1, maxLength: 1500 },
+ mode: {
+ type: "string",
+ enum: ["support", "debt_capture", "debt_review", "world_data", "urgent"],
+ },
+ nextQuestion: {
+ anyOf: [
+ { type: "string", minLength: 1, maxLength: 220 },
+ { type: "null" },
+ ],
+ },
+ risk: {
+ type: "string",
+ enum: ["none", "self_harm", "scam", "illegal_collection", "legal_deadline", "medical"],
+ },
+ actions: {
+ type: "array",
+ minItems: 0,
+ maxItems: 3,
+ items: { type: "string", minLength: 1, maxLength: 180 },
+ },
+ drafts: {
+ type: "array",
+ minItems: 0,
+ maxItems: 6,
+ items: {
+ type: "object",
+ additionalProperties: false,
+ required: [
+ "kind",
+ "customLabel",
+ "currency",
+ "original",
+ "balance",
+ "monthly",
+ "apr",
+ "minimumPayment",
+ "paymentStatus",
+ "remainingMonths",
+ "dueDay",
+ "method",
+ "missingFields",
+ ],
+ properties: {
+ kind: {
+ anyOf: [
+ { type: "string", enum: [...debtKinds] },
+ { type: "null" },
+ ],
+ },
+ customLabel: {
+ anyOf: [
+ { type: "string", maxLength: 80 },
+ { type: "null" },
+ ],
+ },
+ currency: {
+ anyOf: [
+ { type: "string", pattern: "^[A-Z]{3,8}$" },
+ { type: "null" },
+ ],
+ },
+ original: {
+ anyOf: [
+ { type: "number", minimum: 0, maximum: 1_000_000_000_000 },
+ { type: "null" },
+ ],
+ },
+ balance: {
+ anyOf: [
+ { type: "number", minimum: 0, maximum: 1_000_000_000_000 },
+ { type: "null" },
+ ],
+ },
+ monthly: {
+ anyOf: [
+ { type: "number", minimum: 0, maximum: 1_000_000_000_000 },
+ { type: "null" },
+ ],
+ },
+ apr: {
+ anyOf: [
+ { type: "number", minimum: 0, maximum: 1_000 },
+ { type: "null" },
+ ],
+ },
+ minimumPayment: {
+ anyOf: [
+ { type: "number", minimum: 0, maximum: 1_000_000_000_000 },
+ { type: "null" },
+ ],
+ },
+ paymentStatus: {
+ type: "string",
+ enum: ["current", "late", "collection", "unknown"],
+ },
+ remainingMonths: {
+ anyOf: [
+ { type: "integer", minimum: 1, maximum: 1_200 },
+ { type: "null" },
+ ],
+ },
+ dueDay: {
+ anyOf: [
+ { type: "integer", minimum: 1, maximum: 31 },
+ { type: "null" },
+ ],
+ },
+ method: {
+ anyOf: [
+ { type: "string", maxLength: 80 },
+ { type: "null" },
+ ],
+ },
+ missingFields: {
+ type: "array",
+ minItems: 0,
+ maxItems: 12,
+ items: {
+ type: "string",
+ enum: [...missingFields],
+ },
+ },
+ },
+ },
+ },
+ },
+} as const;
+
+const systemPrompt = `
+You are Kian, the bilingual debt-pressure guide inside Debt World.
+Your job is to reduce shame, organize facts, and help the user choose one safe next step.
+
+Hard boundaries:
+- This is educational support, not financial, legal, medical, or tax advice.
+- Never guarantee debt relief, tell a user to stop paying, hide assets, evade a creditor, borrow more, or make an investment.
+- Never invent interest rates, laws, deadlines, creditor policies, world statistics, or facts not present in the supplied JSON.
+- For local law, court papers, limitation periods, collections, insolvency, taxes, or contract penalties: organize documents and questions, then recommend checking a qualified local professional or official service. Do not reach a local legal conclusion.
+- If self-harm or immediate-safety risk appears: respond briefly and compassionately, prioritize contacting local emergency/crisis services or a trusted person now, and do not keep discussing repayment strategy. Do not provide a phone number.
+- If a scam or impersonation risk appears: advise pausing payment, independently verifying the organization through an official channel, and never sharing codes or passwords.
+- Never shame a person or produce an individual "who owes the most" leaderboard.
+- World aggregates may be discussed only when dataReady is true and only from the supplied aggregate fields.
+
+Debt capture:
+- Extract every clearly described debt into drafts, up to six.
+- Treat every draft as unconfirmed. Never claim it was saved.
+- Use only these kinds: mortgage, card, education, medical, car, personal, business, bnpl, informal, other.
+- "Owe a friend/family member" is informal. A novel source can be other with a concise customLabel.
+- Use null for unknown fields and list each unknown field in missingFields.
+- APR means the stated annual percentage rate, not a guessed monthly rate. minimumPayment is the creditor-required minimum, while monthly is what the user currently plans or actually pays.
+- paymentStatus must be current, late, collection, or unknown. remainingMonths is the stated remaining term, never an estimate.
+- If data is missing, ask exactly one short question in nextQuestion: the single most useful missing field across all drafts.
+- If nothing is missing or no debt capture is underway, nextQuestion may be null.
+
+Repayment comparison:
+- When the user asks what to repay first, compare three lenses when the supplied facts allow it: highest APR first, smallest balance first, and cash-flow safety first.
+- Put overdue or collection risk and essential living costs ahead of optional extra payments. If monthly cash flow is not positive, do not recommend an extra-payment amount.
+- Explain which missing APR, minimum-payment, status, or remaining-term facts could change the comparison. Never invent payoff dates or savings.
+
+Response style:
+- Reply in the requested locale (zh or en).
+- Lead with the most useful conclusion. Be warm, direct, and concise.
+- Give at most three concrete actions.
+- Do not repeat all supplied balances unless it helps answer the question.
+`.trim();
+
+type OpenAIResponse = {
+ output_text?: string;
+ output?: Array<{
+ content?: Array<{ type?: string; text?: string }>;
+ }>;
+ usage?: {
+ input_tokens?: number;
+ output_tokens?: number;
+ };
+};
+
+type MiniMaxResponse = {
+ choices?: Array<{
+ message?: {
+ content?: string;
+ reasoning_content?: string;
+ };
+ }>;
+ usage?: {
+ prompt_tokens?: number;
+ completion_tokens?: number;
+ };
+ base_resp?: {
+ status_code?: number;
+ status_msg?: string;
+ };
+};
+
+function runtimeValue(name: string, max = 512) {
+ const workerEnv = env as unknown as Record;
+ const bindingValue = cleanText(workerEnv[name], max);
+ if (bindingValue) return bindingValue;
+ try {
+ return cleanText(process.env?.[name], max);
+ } catch {
+ return "";
+ }
+}
+
+function advisorProviderConfig(): AdvisorProviderConfig | null {
+ const preferred = runtimeValue("AI_PROVIDER", 20).toLowerCase();
+ const minimaxKey = runtimeValue("MINIMAX_API_KEY");
+ const openAIKey = runtimeValue("OPENAI_API_KEY");
+ if (preferred === "minimax") {
+ return minimaxKey
+ ? { provider: "minimax", model: MINIMAX_ADVISOR_MODEL, apiKey: minimaxKey }
+ : null;
+ }
+ if (preferred === "openai") {
+ return openAIKey
+ ? { provider: "openai", model: ADVISOR_MODEL, apiKey: openAIKey }
+ : null;
+ }
+ if (minimaxKey) {
+ return { provider: "minimax", model: MINIMAX_ADVISOR_MODEL, apiKey: minimaxKey };
+ }
+ if (openAIKey) {
+ return { provider: "openai", model: ADVISOR_MODEL, apiKey: openAIKey };
+ }
+ return null;
+}
+
+export function advisorReadiness() {
+ const config = advisorProviderConfig();
+ return config
+ ? { configured: true as const, provider: config.provider, model: config.model }
+ : { configured: false as const, provider: null, model: null };
+}
+
+function boundedNumber(value: unknown, min: number, max: number) {
+ if (typeof value !== "number" || !Number.isFinite(value)) return null;
+ return Math.min(max, Math.max(min, value));
+}
+
+function oneQuestion(value: unknown) {
+ const text = cleanText(value, 220);
+ if (!text) return null;
+ const match = text.match(/^.*?[??]/);
+ return match?.[0] ?? text;
+}
+
+function normalizeDraft(value: unknown): AdvisorDebtDraft | null {
+ if (!value || typeof value !== "object") return null;
+ const draft = value as Record;
+ const kind = typeof draft.kind === "string" && debtKinds.has(draft.kind as DebtKind)
+ ? draft.kind as DebtKind
+ : null;
+ const customLabel = cleanText(draft.customLabel, 80) || null;
+ const currencyText = cleanText(draft.currency, 8).toUpperCase();
+ const currency = /^[A-Z]{3,8}$/.test(currencyText) ? currencyText : null;
+ const rawMissing = Array.isArray(draft.missingFields) ? draft.missingFields : [];
+ return {
+ kind,
+ customLabel,
+ currency,
+ original: boundedNumber(draft.original, 0, 1_000_000_000_000),
+ balance: boundedNumber(draft.balance, 0, 1_000_000_000_000),
+ monthly: boundedNumber(draft.monthly, 0, 1_000_000_000_000),
+ apr: boundedNumber(draft.apr, 0, 1_000),
+ minimumPayment: boundedNumber(draft.minimumPayment, 0, 1_000_000_000_000),
+ paymentStatus: draft.paymentStatus === "current" || draft.paymentStatus === "late" || draft.paymentStatus === "collection"
+ ? draft.paymentStatus
+ : "unknown",
+ remainingMonths: boundedNumber(draft.remainingMonths, 1, 1_200) === null
+ ? null
+ : Math.round(boundedNumber(draft.remainingMonths, 1, 1_200)!),
+ dueDay: boundedNumber(draft.dueDay, 1, 31),
+ method: cleanText(draft.method, 80) || null,
+ missingFields: rawMissing
+ .filter((field): field is AdvisorDebtDraft["missingFields"][number] =>
+ typeof field === "string" && missingFields.has(field as AdvisorDebtDraft["missingFields"][number]))
+ .slice(0, 12),
+ };
+}
+
+function normalizeResult(
+ value: unknown,
+ remainingToday: number,
+ provider: AdvisorProvider,
+ model: string,
+): AdvisorResult {
+ if (!value || typeof value !== "object") {
+ throw new HttpError(502, "The AI reply could not be read. Please try again.");
+ }
+ const result = value as Record;
+ const reply = cleanText(result.reply, 1500);
+ if (!reply) throw new HttpError(502, "The AI reply was empty. Please try again.");
+ const modes = new Set(["support", "debt_capture", "debt_review", "world_data", "urgent"]);
+ const risks = new Set(["none", "self_harm", "scam", "illegal_collection", "legal_deadline", "medical"]);
+ return {
+ reply,
+ mode: typeof result.mode === "string" && modes.has(result.mode)
+ ? result.mode as AdvisorResult["mode"]
+ : "support",
+ nextQuestion: oneQuestion(result.nextQuestion),
+ risk: typeof result.risk === "string" && risks.has(result.risk)
+ ? result.risk as AdvisorResult["risk"]
+ : "none",
+ actions: Array.isArray(result.actions)
+ ? result.actions.map((action) => cleanText(action, 180)).filter(Boolean).slice(0, 3)
+ : [],
+ drafts: Array.isArray(result.drafts)
+ ? result.drafts.map(normalizeDraft).filter((draft): draft is AdvisorDebtDraft => Boolean(draft)).slice(0, 6)
+ : [],
+ remainingToday,
+ provider,
+ model,
+ };
+}
+
+async function safetyIdentifier(vaultId: string) {
+ const digest = await crypto.subtle.digest(
+ "SHA-256",
+ new TextEncoder().encode(`debt-world:${vaultId}`),
+ );
+ return `dw_${Array.from(new Uint8Array(digest), (byte) =>
+ byte.toString(16).padStart(2, "0")).join("").slice(0, 32)}`;
+}
+
+async function reserveDailyUse(vaultId: string) {
+ const db = getD1();
+ const usageDate = new Date().toISOString().slice(0, 10);
+ await db.prepare(
+ `INSERT OR IGNORE INTO ai_daily_usage
+ (id, vault_id, usage_date, request_count, input_tokens, output_tokens)
+ VALUES (?1, ?2, ?3, 0, 0, 0)`,
+ ).bind(crypto.randomUUID(), vaultId, usageDate).run();
+ const updated = await db.prepare(
+ `UPDATE ai_daily_usage
+ SET request_count = request_count + 1, updated_at = CURRENT_TIMESTAMP
+ WHERE vault_id = ?1 AND usage_date = ?2
+ AND request_count < ?3 AND input_tokens < ?4 AND output_tokens < ?5`,
+ ).bind(
+ vaultId,
+ usageDate,
+ ADVISOR_DAILY_REQUEST_LIMIT,
+ ADVISOR_DAILY_INPUT_LIMIT,
+ ADVISOR_DAILY_OUTPUT_LIMIT,
+ ).run();
+ if (Number(updated.meta?.changes ?? 0) < 1) {
+ throw new HttpError(429, "Today's private-test AI limit has been reached. Please try again after 00:00 UTC.");
+ }
+ const row = await db.prepare(
+ `SELECT request_count FROM ai_daily_usage
+ WHERE vault_id = ?1 AND usage_date = ?2 LIMIT 1`,
+ ).bind(vaultId, usageDate).first<{ request_count: number }>();
+ return {
+ usageDate,
+ remainingToday: Math.max(0, ADVISOR_DAILY_REQUEST_LIMIT - Number(row?.request_count ?? ADVISOR_DAILY_REQUEST_LIMIT)),
+ };
+}
+
+async function recordUsage(vaultId: string, usageDate: string, inputTokens: number, outputTokens: number) {
+ await getD1().prepare(
+ `UPDATE ai_daily_usage
+ SET input_tokens = input_tokens + ?1, output_tokens = output_tokens + ?2, updated_at = CURRENT_TIMESTAMP
+ WHERE vault_id = ?3 AND usage_date = ?4`,
+ ).bind(
+ Math.max(0, Math.round(inputTokens)),
+ Math.max(0, Math.round(outputTokens)),
+ vaultId,
+ usageDate,
+ ).run();
+}
+
+function outputText(response: OpenAIResponse) {
+ if (typeof response.output_text === "string" && response.output_text.trim()) {
+ return response.output_text;
+ }
+ for (const item of response.output ?? []) {
+ for (const content of item.content ?? []) {
+ if (content.type === "output_text" && typeof content.text === "string") {
+ return content.text;
+ }
+ }
+ }
+ return "";
+}
+
+async function loadAdvisorContext(vault: VaultRow) {
+ const db = getD1();
+ const [debtResult, storyCount, debtKindsResult, approachesResult] = await Promise.all([
+ db.prepare(
+ `SELECT kind, custom_label, currency, original, balance, monthly, apr, minimum_payment,
+ payment_status, remaining_months, due_day, method
+ FROM debts WHERE vault_id = ?1 ORDER BY created_at ASC LIMIT 12`,
+ ).bind(vault.id).all<{
+ kind: string;
+ custom_label: string | null;
+ currency: string;
+ original: number;
+ balance: number;
+ monthly: number;
+ apr: number | null;
+ minimum_payment: number | null;
+ payment_status: string;
+ remaining_months: number | null;
+ due_day: number;
+ method: string;
+ }>(),
+ db.prepare("SELECT COUNT(*) AS count FROM public_stories WHERE status = 'published'")
+ .first<{ count: number }>(),
+ db.prepare(
+ `SELECT debt_kind AS label, COUNT(*) AS count FROM public_stories
+ WHERE status = 'published' GROUP BY debt_kind ORDER BY count DESC, debt_kind ASC LIMIT 5`,
+ ).all<{ label: string; count: number }>(),
+ db.prepare(
+ `SELECT repayment_approach AS label, COUNT(*) AS count FROM public_stories
+ WHERE status = 'published' GROUP BY repayment_approach ORDER BY count DESC, repayment_approach ASC LIMIT 5`,
+ ).all<{ label: string; count: number }>(),
+ ]);
+ const reviewedStoryCount = Number(storyCount?.count ?? 0);
+ const dataReady = reviewedStoryCount >= 30;
+ return {
+ profile: {
+ countryCode: vault.country_code,
+ displayCurrency: vault.display_currency,
+ monthlyIncome: vault.monthly_income,
+ monthlyExpenses: vault.monthly_expenses,
+ ageBand: vault.age_band || null,
+ mbti: vault.mbti || null,
+ zodiac: vault.zodiac || null,
+ selfDescription: vault.self_description || null,
+ repaymentPlan: vault.repayment_plan || null,
+ repaymentOutlook: vault.repayment_outlook || null,
+ incomePlan: vault.income_plan || null,
+ },
+ debts: debtResult.results.map((debt) => ({
+ kind: debt.kind,
+ customLabel: debt.custom_label,
+ currency: debt.currency,
+ original: debt.original,
+ balance: debt.balance,
+ monthly: debt.monthly,
+ apr: debt.apr,
+ minimumPayment: debt.minimum_payment,
+ paymentStatus: debt.payment_status,
+ remainingMonths: debt.remaining_months,
+ dueDay: debt.due_day,
+ method: debt.method,
+ })),
+ worldData: {
+ reviewedStoryCount,
+ dataReady,
+ minimumReviewedStories: 30,
+ debtKinds: dataReady ? debtKindsResult.results : [],
+ repaymentApproaches: dataReady ? approachesResult.results : [],
+ individualLargestDebtorLeaderboard: "not_collected_or_published",
+ },
+ };
+}
+
+export async function runAdvisor(
+ vault: VaultRow,
+ userQuestion: string,
+ locale: Locale,
+) {
+ const config = advisorProviderConfig();
+ if (!config) {
+ throw new HttpError(
+ 503,
+ locale === "zh"
+ ? "真实 AI 密钥尚未进入运行环境,本机规则分析仍可使用。"
+ : "The real-AI key is not available in the runtime yet. The on-device guide remains available.",
+ );
+ }
+ const context = await loadAdvisorContext(vault);
+ const reservation = await reserveDailyUse(vault.id);
+ const privacyNote = "No recovery code, alias, exact city, message history, or public identity is supplied.";
+ const input = JSON.stringify({
+ locale,
+ userQuestion,
+ ...context,
+ privacyNote,
+ });
+ const providerResult = config.provider === "minimax"
+ ? await callMiniMax(config, input, locale)
+ : await callOpenAI(config, input, vault.id, locale);
+ await recordUsage(
+ vault.id,
+ reservation.usageDate,
+ providerResult.inputTokens,
+ providerResult.outputTokens,
+ );
+ try {
+ return normalizeResult(
+ parseProviderJson(providerResult.text),
+ reservation.remainingToday,
+ config.provider,
+ config.model,
+ );
+ } catch (error) {
+ if (error instanceof HttpError) throw error;
+ throw new HttpError(
+ 502,
+ locale === "zh"
+ ? "AI 回答暂时无法解析,请换一种简短说法再试一次。"
+ : "The AI reply could not be read. Try again with a shorter wording.",
+ );
+ }
+}
+
+function parseProviderJson(source: string) {
+ const trimmed = source
+ .trim()
+ .replace(/^```(?:json)?\s*/i, "")
+ .replace(/\s*```$/i, "");
+ try {
+ return JSON.parse(trimmed) as unknown;
+ } catch {
+ const firstBrace = trimmed.indexOf("{");
+ const lastBrace = trimmed.lastIndexOf("}");
+ if (firstBrace >= 0 && lastBrace > firstBrace) {
+ return JSON.parse(trimmed.slice(firstBrace, lastBrace + 1)) as unknown;
+ }
+ throw new Error("No JSON object in provider response.");
+ }
+}
+
+function providerHttpError(status: number, locale: Locale) {
+ if (status === 401 || status === 403) {
+ return new HttpError(
+ 503,
+ locale === "zh"
+ ? "AI 密钥无效、已失效或服务区域不匹配,请检查服务商控制台。"
+ : "The AI key is invalid, expired, or belongs to a different service region.",
+ );
+ }
+ if (status === 429) {
+ return new HttpError(
+ 503,
+ locale === "zh"
+ ? "AI 套餐窗口额度或并发限制已达到,请稍后再试。"
+ : "The AI plan window or concurrency limit has been reached. Please try again later.",
+ );
+ }
+ return new HttpError(
+ 502,
+ locale === "zh"
+ ? "AI 服务暂时没有成功响应,请稍后再试。"
+ : "The AI service did not respond successfully. Please try again later.",
+ );
+}
+
+async function callOpenAI(
+ config: AdvisorProviderConfig,
+ input: string,
+ vaultId: string,
+ locale: Locale,
+) {
+ const response = await fetch("https://api.openai.com/v1/responses", {
+ method: "POST",
+ headers: {
+ "Authorization": `Bearer ${config.apiKey}`,
+ "Content-Type": "application/json",
+ },
+ body: JSON.stringify({
+ model: config.model,
+ store: false,
+ safety_identifier: await safetyIdentifier(vaultId),
+ reasoning: { effort: "low" },
+ max_output_tokens: 1200,
+ text: {
+ verbosity: "low",
+ format: {
+ type: "json_schema",
+ name: "debt_world_advisor",
+ strict: true,
+ schema: responseSchema,
+ },
+ },
+ input: [
+ {
+ role: "system",
+ content: [{ type: "input_text", text: systemPrompt }],
+ },
+ {
+ role: "user",
+ content: [{ type: "input_text", text: input }],
+ },
+ ],
+ }),
+ });
+ if (!response.ok) {
+ throw providerHttpError(response.status, locale);
+ }
+ const providerResponse = await response.json() as OpenAIResponse;
+ return {
+ text: outputText(providerResponse),
+ inputTokens: Number(providerResponse.usage?.input_tokens ?? 0),
+ outputTokens: Number(providerResponse.usage?.output_tokens ?? 0),
+ };
+}
+
+async function callMiniMax(
+ config: AdvisorProviderConfig,
+ input: string,
+ locale: Locale,
+) {
+ const globalRegion = runtimeValue("MINIMAX_REGION", 20).toLowerCase() === "global";
+ const baseUrl = globalRegion ? "https://api.minimax.io/v1" : "https://api.minimaxi.com/v1";
+ const response = await fetch(`${baseUrl}/chat/completions`, {
+ method: "POST",
+ headers: {
+ "Authorization": `Bearer ${config.apiKey}`,
+ "Content-Type": "application/json",
+ },
+ body: JSON.stringify({
+ model: config.model,
+ stream: false,
+ temperature: 1,
+ top_p: 0.95,
+ max_tokens: 1200,
+ messages: [
+ {
+ role: "system",
+ content: `${systemPrompt}
+
+Output contract for this request:
+- Return exactly one JSON object and no markdown fence.
+- Follow this JSON Schema as closely as possible:
+${JSON.stringify(responseSchema)}`,
+ },
+ { role: "user", content: input },
+ ],
+ }),
+ });
+ if (!response.ok) {
+ throw providerHttpError(response.status, locale);
+ }
+ const providerResponse = await response.json() as MiniMaxResponse;
+ const providerStatus = Number(providerResponse.base_resp?.status_code ?? 0);
+ if (providerStatus !== 0) {
+ if (providerStatus === 1004) throw providerHttpError(401, locale);
+ if (providerStatus === 1002 || providerStatus === 1008 || providerStatus === 1039 || providerStatus === 1041) {
+ throw providerHttpError(429, locale);
+ }
+ throw providerHttpError(502, locale);
+ }
+ return {
+ text: cleanText(providerResponse.choices?.[0]?.message?.content, 10_000),
+ inputTokens: Number(providerResponse.usage?.prompt_tokens ?? 0),
+ outputTokens: Number(providerResponse.usage?.completion_tokens ?? 0),
+ };
+}
diff --git a/lib/beta-server.ts b/lib/beta-server.ts
new file mode 100644
index 0000000..e5cba2b
--- /dev/null
+++ b/lib/beta-server.ts
@@ -0,0 +1,120 @@
+import { env } from "cloudflare:workers";
+import { getD1 } from "@/db";
+import type { Locale } from "@/lib/debt-world-types";
+import { HttpError, cleanText } from "@/lib/vault-server";
+
+export const BETA_CONSENT_VERSION = "beta-2026-07-30";
+
+function runtimeValue(key: string, max = 200) {
+ const workerEnv = env as unknown as Record;
+ return cleanText(workerEnv[key], max);
+}
+
+function runtimeBoolean(key: string, fallback: boolean) {
+ const value = runtimeValue(key, 12).toLowerCase();
+ if (value === "true" || value === "1" || value === "yes") return true;
+ if (value === "false" || value === "0" || value === "no") return false;
+ return fallback;
+}
+
+function configuredMaxUses() {
+ const parsed = Number(runtimeValue("BETA_INVITE_MAX_USES", 8));
+ return Number.isFinite(parsed) ? Math.min(500, Math.max(1, Math.round(parsed))) : 30;
+}
+
+function configuredDailySignupLimit() {
+ const parsed = Number(runtimeValue("BETA_DAILY_SIGNUP_LIMIT", 8));
+ return Number.isFinite(parsed) ? Math.min(2_000, Math.max(5, Math.round(parsed))) : 100;
+}
+
+async function digestText(value: string) {
+ const digest = await crypto.subtle.digest("SHA-256", new TextEncoder().encode(value));
+ return Array.from(new Uint8Array(digest), (byte) => byte.toString(16).padStart(2, "0")).join("");
+}
+
+function constantEqual(left: string, right: string) {
+ if (left.length !== right.length) return false;
+ let difference = 0;
+ for (let index = 0; index < left.length; index += 1) {
+ difference |= left.charCodeAt(index) ^ right.charCodeAt(index);
+ }
+ return difference === 0;
+}
+
+export function normalizeInviteCode(value: unknown) {
+ return cleanText(value, 80).toUpperCase().replace(/[^A-Z0-9-]/g, "");
+}
+
+export async function betaPublicState() {
+ const inviteCode = normalizeInviteCode(runtimeValue("BETA_INVITE_CODE", 80));
+ const inviteRequired = runtimeBoolean("BETA_INVITES_REQUIRED", false);
+ const environmentSignups = runtimeBoolean("BETA_SIGNUPS_ENABLED", true);
+ const [override, today] = await Promise.all([
+ getD1().prepare("SELECT signups_enabled FROM beta_runtime_settings WHERE id = 'default' LIMIT 1").first<{ signups_enabled: number }>(),
+ getD1().prepare("SELECT COUNT(*) AS count FROM accounts WHERE datetime(created_at) >= datetime('now', 'start of day')").first<{ count: number }>(),
+ ]);
+ return {
+ signupsEnabled: override ? Boolean(override.signups_enabled) : environmentSignups,
+ inviteRequired,
+ inviteConfigured: Boolean(inviteCode),
+ maxUses: configuredMaxUses(),
+ dailySignupLimit: configuredDailySignupLimit(),
+ signupsToday: Number(today?.count ?? 0),
+ };
+}
+
+export async function assertAccountSignupOpen() {
+ const state = await betaPublicState();
+ if (!state.signupsEnabled) throw new HttpError(503, "Public-beta registration is temporarily paused.");
+ if (state.signupsToday >= state.dailySignupLimit) {
+ throw new HttpError(429, "Today’s public-beta registration limit has been reached. Please try again tomorrow.");
+ }
+ return state;
+}
+
+export async function consumeBetaInvite(input: {
+ inviteCode?: unknown;
+ betaConsent?: unknown;
+ locale: Locale;
+}) {
+ const state = await betaPublicState();
+ const zh = input.locale === "zh";
+ if (!state.signupsEnabled) {
+ throw new HttpError(503, zh ? "本轮私测名额已暂停新增,请等待下一轮邀请。" : "New beta places are paused. Please wait for the next invitation round.");
+ }
+ if (!state.inviteRequired) return null;
+ if (!state.inviteConfigured) {
+ throw new HttpError(503, zh ? "邀请码系统还在准备中,请稍后再试。" : "The invitation system is still being prepared.");
+ }
+ if (input.betaConsent !== true) {
+ throw new HttpError(400, zh ? "请先确认私测说明与数据边界。" : "Please confirm the beta notice and data boundaries first.");
+ }
+ const supplied = normalizeInviteCode(input.inviteCode);
+ const expected = normalizeInviteCode(runtimeValue("BETA_INVITE_CODE", 80));
+ const [suppliedDigest, expectedDigest] = await Promise.all([digestText(supplied), digestText(expected)]);
+ if (!supplied || !constantEqual(suppliedDigest, expectedDigest)) {
+ throw new HttpError(403, zh ? "邀请码不正确,请向邀请人核对。" : "That invitation code is not valid. Check it with the person who invited you.");
+ }
+ const db = getD1();
+ await db.prepare(
+ `INSERT OR IGNORE INTO beta_invite_counters (invite_digest, uses, max_uses)
+ VALUES (?1, 0, ?2)`,
+ ).bind(expectedDigest, state.maxUses).run();
+ const consumed = await db.prepare(
+ `UPDATE beta_invite_counters
+ SET uses = uses + 1, max_uses = ?2, updated_at = CURRENT_TIMESTAMP
+ WHERE invite_digest = ?1 AND uses < ?2`,
+ ).bind(expectedDigest, state.maxUses).run();
+ if (Number(consumed.meta?.changes ?? 0) < 1) {
+ throw new HttpError(409, zh ? "这一轮邀请码名额已经用完。" : "This invitation round is full.");
+ }
+ return { inviteDigest: expectedDigest, consentVersion: BETA_CONSENT_VERSION };
+}
+
+export function cleanBetaFeedback(value: unknown) {
+ return cleanText(value, 1_200)
+ .replace(/\b[A-Z0-9._%+-]+@[A-Z0-9.-]+\.[A-Z]{2,}\b/gi, "[contact hidden]")
+ .replace(/(?:https?:\/\/|www\.)\S+/gi, "[link hidden]")
+ .replace(/\+?\d[\d\s()-]{6,}\d/g, "[contact hidden]")
+ .trim();
+}
diff --git a/lib/community-safety.ts b/lib/community-safety.ts
new file mode 100644
index 0000000..4308208
--- /dev/null
+++ b/lib/community-safety.ts
@@ -0,0 +1,113 @@
+import { env } from "cloudflare:workers";
+import { getD1 } from "@/db";
+import { requireAccount, sha256Hex } from "@/lib/account-server";
+import { HttpError, cleanText } from "@/lib/vault-server";
+
+const communityLimits = {
+ publish: 3,
+ encourage: 30,
+ report: 10,
+} as const;
+
+export type CommunityLimitedAction = keyof typeof communityLimits;
+
+export function cleanModerationNote(value: unknown) {
+ return cleanText(value, 240)
+ .replace(/\b[A-Z0-9._%+-]+@[A-Z0-9.-]+\.[A-Z]{2,}\b/gi, "[private detail hidden]")
+ .replace(/(?:https?:\/\/|www\.)\S+/gi, "[private detail hidden]")
+ .replace(/\+?\d[\d\s()-]{6,}\d/g, "[private detail hidden]")
+ .replace(/\b\d{4,}\b/g, "[private detail hidden]")
+ .trim();
+}
+
+export async function consumeCommunityRateLimit(vaultId: string, action: CommunityLimitedAction) {
+ const db = getD1();
+ const windowKey = new Date().toISOString().slice(0, 10);
+ const id = crypto.randomUUID();
+ await db.prepare(
+ `INSERT OR IGNORE INTO community_rate_limits
+ (id, vault_id, action, window_key, count)
+ VALUES (?1, ?2, ?3, ?4, 0)`,
+ ).bind(id, vaultId, action, windowKey).run();
+ const updated = await db.prepare(
+ `UPDATE community_rate_limits
+ SET count = count + 1, updated_at = CURRENT_TIMESTAMP
+ WHERE vault_id = ?1 AND action = ?2 AND window_key = ?3 AND count < ?4`,
+ ).bind(vaultId, action, windowKey, communityLimits[action]).run();
+ if (Number(updated.meta?.changes ?? 0) < 1) {
+ const labels = {
+ publish: "anonymous story submissions",
+ encourage: "light gifts",
+ report: "story reports",
+ };
+ throw new HttpError(429, `Today's safety limit for ${labels[action]} has been reached. Please try again after 00:00 UTC.`);
+ }
+}
+
+function ownerEmail() {
+ const workerEnv = env as unknown as Record;
+ const configuredOwner = String(workerEnv.OWNER_ADMIN_EMAIL ?? "").trim().toLowerCase();
+ if (configuredOwner) return configuredOwner;
+ return String(workerEnv.COMMUNITY_ADMIN_EMAILS ?? "").split(",")[0]?.trim().toLowerCase() ?? "";
+}
+
+async function eligibleOwner(request: Request) {
+ const email = cleanText(request.headers.get("oai-authenticated-user-email"), 320).toLowerCase();
+ if (!email || !ownerEmail() || email !== ownerEmail()) throw new HttpError(404, "Not found.");
+ return { emailDigest: await sha256Hex(email) };
+}
+
+export async function ownerAdminSession(request: Request) {
+ const [owner, account] = await Promise.all([eligibleOwner(request), requireAccount(request)]);
+ const registered = await getD1().prepare(
+ "SELECT email_digest, account_id, activated_at, last_seen_at FROM owner_admins WHERE id = 'owner' LIMIT 1",
+ ).first<{ email_digest: string; account_id: string | null; activated_at: string; last_seen_at: string }>();
+ if (registered && registered.email_digest !== owner.emailDigest) throw new HttpError(409, "The owner slot is already locked.");
+ if (registered?.account_id && registered.account_id !== account.id) throw new HttpError(404, "Not found.");
+ return {
+ eligible: true,
+ registered: Boolean(registered?.account_id === account.id),
+ accountUsername: account.username,
+ accountCode: account.user_code,
+ activatedAt: registered?.activated_at ?? null,
+ };
+}
+
+export async function registerOwnerAdmin(request: Request) {
+ const [owner, account] = await Promise.all([eligibleOwner(request), requireAccount(request)]);
+ const db = getD1();
+ const existing = await db.prepare(
+ "SELECT email_digest, account_id, activated_at FROM owner_admins WHERE id = 'owner' LIMIT 1",
+ ).first<{ email_digest: string; account_id: string | null; activated_at: string }>();
+ if (existing && existing.email_digest !== owner.emailDigest) throw new HttpError(409, "The owner slot is already locked.");
+ if (existing?.account_id && existing.account_id !== account.id) throw new HttpError(409, "The owner account is already bound.");
+ if (!existing) {
+ await db.prepare(
+ `INSERT INTO owner_admins (id, email_digest, account_id, role)
+ VALUES ('owner', ?1, ?2, 'owner')`,
+ ).bind(owner.emailDigest, account.id).run();
+ } else if (!existing.account_id) {
+ await db.prepare(
+ "UPDATE owner_admins SET account_id = ?1, last_seen_at = CURRENT_TIMESTAMP WHERE id = 'owner' AND account_id IS NULL",
+ ).bind(account.id).run();
+ }
+ const registered = await db.prepare(
+ "SELECT email_digest, account_id, activated_at FROM owner_admins WHERE id = 'owner' LIMIT 1",
+ ).first<{ email_digest: string; account_id: string | null; activated_at: string }>();
+ if (!registered || registered.email_digest !== owner.emailDigest || registered.account_id !== account.id) throw new HttpError(409, "The owner account could not be bound.");
+ return { eligible: true, registered: true, accountUsername: account.username, accountCode: account.user_code, activatedAt: registered.activated_at };
+}
+
+export async function requireCommunityAdmin(request: Request) {
+ const [owner, account] = await Promise.all([eligibleOwner(request), requireAccount(request)]);
+ const registered = await getD1().prepare(
+ "SELECT email_digest, account_id FROM owner_admins WHERE id = 'owner' AND role = 'owner' LIMIT 1",
+ ).first<{ email_digest: string; account_id: string | null }>();
+ if (!registered || registered.email_digest !== owner.emailDigest || registered.account_id !== account.id) throw new HttpError(404, "Not found.");
+ await getD1().prepare(
+ "UPDATE owner_admins SET last_seen_at = CURRENT_TIMESTAMP WHERE id = 'owner'",
+ ).run();
+ return {
+ actorDigest: (await sha256Hex(`${owner.emailDigest}:${account.id}`)).slice(0, 24),
+ };
+}
diff --git a/lib/country-currency.ts b/lib/country-currency.ts
new file mode 100644
index 0000000..2734119
--- /dev/null
+++ b/lib/country-currency.ts
@@ -0,0 +1,78 @@
+import type { Locale } from "./debt-world-types";
+
+export type CountryOption = {
+ code: string;
+ currency: string;
+ zh: string;
+ en: string;
+};
+
+export const countryOptions: CountryOption[] = [
+ { code: "CN", currency: "CNY", zh: "中国", en: "China" },
+ { code: "US", currency: "USD", zh: "美国", en: "United States" },
+ { code: "GB", currency: "GBP", zh: "英国", en: "United Kingdom" },
+ { code: "JP", currency: "JPY", zh: "日本", en: "Japan" },
+ { code: "KR", currency: "KRW", zh: "韩国", en: "South Korea" },
+ { code: "IN", currency: "INR", zh: "印度", en: "India" },
+ { code: "BR", currency: "BRL", zh: "巴西", en: "Brazil" },
+ { code: "CA", currency: "CAD", zh: "加拿大", en: "Canada" },
+ { code: "AU", currency: "AUD", zh: "澳大利亚", en: "Australia" },
+ { code: "DE", currency: "EUR", zh: "德国", en: "Germany" },
+ { code: "FR", currency: "EUR", zh: "法国", en: "France" },
+ { code: "ES", currency: "EUR", zh: "西班牙", en: "Spain" },
+ { code: "IT", currency: "EUR", zh: "意大利", en: "Italy" },
+ { code: "NL", currency: "EUR", zh: "荷兰", en: "Netherlands" },
+ { code: "PT", currency: "EUR", zh: "葡萄牙", en: "Portugal" },
+ { code: "IE", currency: "EUR", zh: "爱尔兰", en: "Ireland" },
+ { code: "GR", currency: "EUR", zh: "希腊", en: "Greece" },
+ { code: "HK", currency: "HKD", zh: "中国香港", en: "Hong Kong" },
+ { code: "TW", currency: "TWD", zh: "中国台湾", en: "Taiwan" },
+ { code: "SG", currency: "SGD", zh: "新加坡", en: "Singapore" },
+ { code: "MY", currency: "MYR", zh: "马来西亚", en: "Malaysia" },
+ { code: "ID", currency: "IDR", zh: "印度尼西亚", en: "Indonesia" },
+ { code: "TH", currency: "THB", zh: "泰国", en: "Thailand" },
+ { code: "VN", currency: "VND", zh: "越南", en: "Vietnam" },
+ { code: "PH", currency: "PHP", zh: "菲律宾", en: "Philippines" },
+ { code: "PK", currency: "PKR", zh: "巴基斯坦", en: "Pakistan" },
+ { code: "BD", currency: "BDT", zh: "孟加拉国", en: "Bangladesh" },
+ { code: "AE", currency: "AED", zh: "阿联酋", en: "United Arab Emirates" },
+ { code: "SA", currency: "SAR", zh: "沙特阿拉伯", en: "Saudi Arabia" },
+ { code: "TR", currency: "TRY", zh: "土耳其", en: "Türkiye" },
+ { code: "IL", currency: "ILS", zh: "以色列", en: "Israel" },
+ { code: "EG", currency: "EGP", zh: "埃及", en: "Egypt" },
+ { code: "ZA", currency: "ZAR", zh: "南非", en: "South Africa" },
+ { code: "NG", currency: "NGN", zh: "尼日利亚", en: "Nigeria" },
+ { code: "KE", currency: "KES", zh: "肯尼亚", en: "Kenya" },
+ { code: "MA", currency: "MAD", zh: "摩洛哥", en: "Morocco" },
+ { code: "MX", currency: "MXN", zh: "墨西哥", en: "Mexico" },
+ { code: "AR", currency: "ARS", zh: "阿根廷", en: "Argentina" },
+ { code: "CL", currency: "CLP", zh: "智利", en: "Chile" },
+ { code: "CO", currency: "COP", zh: "哥伦比亚", en: "Colombia" },
+ { code: "PE", currency: "PEN", zh: "秘鲁", en: "Peru" },
+ { code: "NZ", currency: "NZD", zh: "新西兰", en: "New Zealand" },
+ { code: "CH", currency: "CHF", zh: "瑞士", en: "Switzerland" },
+ { code: "SE", currency: "SEK", zh: "瑞典", en: "Sweden" },
+ { code: "NO", currency: "NOK", zh: "挪威", en: "Norway" },
+ { code: "DK", currency: "DKK", zh: "丹麦", en: "Denmark" },
+ { code: "PL", currency: "PLN", zh: "波兰", en: "Poland" },
+ { code: "CZ", currency: "CZK", zh: "捷克", en: "Czechia" },
+ { code: "HU", currency: "HUF", zh: "匈牙利", en: "Hungary" },
+ { code: "RO", currency: "RON", zh: "罗马尼亚", en: "Romania" },
+ { code: "RU", currency: "RUB", zh: "俄罗斯", en: "Russia" },
+ { code: "UA", currency: "UAH", zh: "乌克兰", en: "Ukraine" },
+ { code: "OTHER", currency: "USD", zh: "其他国家或地区", en: "Another country or region" },
+];
+
+export const currencyOptions = Array.from(new Set(countryOptions.map((country) => country.currency))).sort();
+
+export function countryName(code: string | undefined, customName: string | undefined, locale: Locale) {
+ const found = countryOptions.find((country) => country.code === code);
+ if (found && found.code !== "OTHER") return found[locale];
+ return customName?.trim() || (locale === "zh" ? "未选择" : "Not selected");
+}
+
+export function countryFlag(code: string | undefined) {
+ if (!code || code.length !== 2) return "◎";
+ return String.fromCodePoint(...code.toUpperCase().split("").map((letter) => 127397 + letter.charCodeAt(0)));
+}
+
diff --git a/lib/debt-world-types.ts b/lib/debt-world-types.ts
new file mode 100644
index 0000000..e2f6511
--- /dev/null
+++ b/lib/debt-world-types.ts
@@ -0,0 +1,138 @@
+export type Locale = "zh" | "en";
+export type SharingMode = "private" | "range";
+export type DebtPaymentStatus = "current" | "late" | "collection" | "unknown";
+
+export type DebtKind =
+ | "mortgage"
+ | "card"
+ | "education"
+ | "medical"
+ | "car"
+ | "personal"
+ | "business"
+ | "bnpl"
+ | "informal"
+ | "other";
+
+export type PaymentHistory = {
+ confirmedAt: string;
+ cashPayment: number;
+ newBalance: number;
+ source?: "self_report" | "prepayment" | "lucky_income";
+ incomeType?: string;
+ eventDate?: string;
+};
+
+export type Debt = {
+ id: string;
+ kind: DebtKind;
+ customLabel?: string;
+ currency: string;
+ original: number;
+ balance: number;
+ monthly: number;
+ apr?: number | null;
+ minimumPayment?: number | null;
+ paymentStatus?: DebtPaymentStatus;
+ remainingMonths?: number | null;
+ dueDay: number;
+ method: string;
+ sharingMode?: SharingMode;
+ lastPaidAt?: string;
+ payments: number;
+ history?: PaymentHistory[];
+};
+
+export type Profile = {
+ alias: string;
+ region: string;
+ pressure: string;
+ ageBand: string;
+ gender: string;
+ mbti: string;
+ zodiac: string;
+ selfDescription: string;
+ repaymentPlan: string;
+ repaymentOutlook: string;
+ incomePlan: string;
+ countryCode: string;
+ countryName: string;
+ displayCurrency: string;
+ monthlyIncome: number;
+ monthlyExpenses: number;
+};
+
+export type Position = {
+ x: number;
+ y: number;
+};
+
+export type VaultPayload = {
+ profile: Profile;
+ position: Position;
+ locale: Locale;
+ discoveryConsent: boolean;
+ debts: Debt[];
+ policyAcceptances?: Array<{ policyKey: string; policyVersion: string; acceptedAt: string }>;
+ betaEnrollment?: { consentVersion: string; createdAt: string } | null;
+ betaFeedback?: Array<{ category: string; rating: number; message: string; pagePath: string; status: string; createdAt: string }>;
+ createdAt?: string;
+ updatedAt?: string;
+};
+
+export type CloudState = "checking" | "local" | "syncing" | "synced" | "error";
+
+export type AdvisorRisk =
+ | "none"
+ | "self_harm"
+ | "scam"
+ | "illegal_collection"
+ | "legal_deadline"
+ | "medical";
+
+export type AdvisorDebtDraft = {
+ kind: DebtKind | null;
+ customLabel: string | null;
+ currency: string | null;
+ original: number | null;
+ balance: number | null;
+ monthly: number | null;
+ apr: number | null;
+ minimumPayment: number | null;
+ paymentStatus: DebtPaymentStatus;
+ remainingMonths: number | null;
+ dueDay: number | null;
+ method: string | null;
+ missingFields: Array<
+ | "kind"
+ | "customLabel"
+ | "currency"
+ | "original"
+ | "balance"
+ | "monthly"
+ | "apr"
+ | "minimumPayment"
+ | "paymentStatus"
+ | "remainingMonths"
+ | "dueDay"
+ | "method"
+ >;
+};
+
+export type AdvisorResult = {
+ reply: string;
+ mode: "support" | "debt_capture" | "debt_review" | "world_data" | "urgent";
+ nextQuestion: string | null;
+ risk: AdvisorRisk;
+ actions: string[];
+ drafts: AdvisorDebtDraft[];
+ remainingToday: number;
+ provider: "openai" | "minimax";
+ model: string;
+};
+
+export type AdvisorReadiness = {
+ configured: boolean;
+ provider: "openai" | "minimax" | null;
+ model: string | null;
+};
diff --git a/lib/exchange-rates.ts b/lib/exchange-rates.ts
new file mode 100644
index 0000000..15e83d8
--- /dev/null
+++ b/lib/exchange-rates.ts
@@ -0,0 +1,62 @@
+export type ExchangeRateMap = Record;
+
+// Display-only fallback values. The live endpoint replaces these whenever available.
+export const fallbackUsdRates: ExchangeRateMap = {
+ USD: 1,
+ CNY: 7.2,
+ EUR: 0.86,
+ GBP: 0.75,
+ JPY: 154,
+ KRW: 1380,
+ INR: 88,
+ BRL: 5.5,
+ AUD: 1.52,
+ CAD: 1.37,
+ HKD: 7.82,
+ TWD: 31.5,
+ SGD: 1.28,
+ MYR: 4.3,
+ IDR: 16300,
+ THB: 32.5,
+ VND: 26100,
+ PHP: 58.5,
+ PKR: 280,
+ BDT: 122,
+ AED: 3.6725,
+ SAR: 3.75,
+ TRY: 41,
+ ILS: 3.35,
+ EGP: 49,
+ ZAR: 17.8,
+ NGN: 1500,
+ KES: 129,
+ MAD: 9.7,
+ MXN: 18.6,
+ ARS: 1350,
+ CLP: 950,
+ COP: 4100,
+ PEN: 3.55,
+ NZD: 1.68,
+ CHF: 0.8,
+ SEK: 9.6,
+ NOK: 10.1,
+ DKK: 6.4,
+ PLN: 3.7,
+ CZK: 21,
+ HUF: 340,
+ RON: 4.35,
+ RUB: 82,
+ UAH: 41.5,
+};
+
+export function convertCurrency(value: number, from: string, to: string, rates: ExchangeRateMap) {
+ if (!Number.isFinite(value)) return 0;
+ const source = from.toUpperCase();
+ const target = to.toUpperCase();
+ if (source === target) return value;
+ const sourceRate = rates[source];
+ const targetRate = rates[target];
+ if (!sourceRate || !targetRate) return value;
+ return (value / sourceRate) * targetRate;
+}
+
diff --git a/lib/referral-server.ts b/lib/referral-server.ts
new file mode 100644
index 0000000..8510146
--- /dev/null
+++ b/lib/referral-server.ts
@@ -0,0 +1,138 @@
+import { getD1 } from "@/db";
+import { cleanText } from "@/lib/vault-server";
+
+const REFERRAL_ALPHABET = "ABCDEFGHJKLMNPQRSTUVWXYZ23456789";
+const INVITER_SHORE_VALUE = 25;
+const INVITER_STARLIGHT = 5;
+const INVITED_SHORE_VALUE = 10;
+const INVITED_STARLIGHT = 2;
+
+function normalizeReferralCode(value: unknown) {
+ return cleanText(value, 40).toUpperCase().replace(/[^A-Z0-9-]/g, "");
+}
+
+function randomReferralCode() {
+ const bytes = crypto.getRandomValues(new Uint8Array(8));
+ return `SHORE-${Array.from(bytes, (byte) => REFERRAL_ALPHABET[byte % REFERRAL_ALPHABET.length]).join("")}`;
+}
+
+async function ensureReferralCode(vaultId: string) {
+ const db = getD1();
+ const existing = await db.prepare(
+ "SELECT id, code FROM referral_codes WHERE vault_id = ?1 AND status = 'active' LIMIT 1",
+ ).bind(vaultId).first<{ id: string; code: string }>();
+ if (existing) return existing;
+ for (let attempt = 0; attempt < 6; attempt += 1) {
+ const id = crypto.randomUUID();
+ const code = randomReferralCode();
+ await db.prepare(
+ `INSERT OR IGNORE INTO referral_codes (id, vault_id, code, status)
+ VALUES (?1, ?2, ?3, 'active')`,
+ ).bind(id, vaultId, code).run();
+ const created = await db.prepare(
+ "SELECT id, code FROM referral_codes WHERE vault_id = ?1 AND status = 'active' LIMIT 1",
+ ).bind(vaultId).first<{ id: string; code: string }>();
+ if (created) return created;
+ }
+ throw new Error("The referral link could not be created.");
+}
+
+export async function getReferralState(vaultId: string) {
+ const db = getD1();
+ const code = await ensureReferralCode(vaultId);
+ const counts = await db.prepare(
+ `SELECT COUNT(*) AS total,
+ SUM(CASE WHEN status = 'rewarded' THEN 1 ELSE 0 END) AS activated
+ FROM referral_relationships WHERE inviter_vault_id = ?1`,
+ ).bind(vaultId).first<{ total: number; activated: number }>();
+ return {
+ code: code.code,
+ invited: Number(counts?.total ?? 0),
+ activated: Number(counts?.activated ?? 0),
+ pending: Math.max(0, Number(counts?.total ?? 0) - Number(counts?.activated ?? 0)),
+ rewards: {
+ inviterShoreValue: INVITER_SHORE_VALUE,
+ inviterStarlight: INVITER_STARLIGHT,
+ invitedShoreValue: INVITED_SHORE_VALUE,
+ invitedStarlight: INVITED_STARLIGHT,
+ },
+ };
+}
+
+export async function attachReferral(invitedVaultId: string, value: unknown) {
+ const code = normalizeReferralCode(value);
+ if (!code) return false;
+ const db = getD1();
+ const inviter = await db.prepare(
+ `SELECT id, vault_id FROM referral_codes
+ WHERE code = ?1 AND status = 'active' LIMIT 1`,
+ ).bind(code).first<{ id: string; vault_id: string }>();
+ if (!inviter || inviter.vault_id === invitedVaultId) return false;
+ const inserted = await db.prepare(
+ `INSERT OR IGNORE INTO referral_relationships
+ (id, inviter_vault_id, invited_vault_id, code_id, status)
+ VALUES (?1, ?2, ?3, ?4, 'pending')`,
+ ).bind(crypto.randomUUID(), inviter.vault_id, invitedVaultId, inviter.id).run();
+ return Number(inserted.meta?.changes ?? 0) > 0;
+}
+
+export async function qualifyReferral(invitedVaultId: string) {
+ const db = getD1();
+ const relationship = await db.prepare(
+ `SELECT id, inviter_vault_id, invited_vault_id, status
+ FROM referral_relationships WHERE invited_vault_id = ?1 LIMIT 1`,
+ ).bind(invitedVaultId).first<{
+ id: string;
+ inviter_vault_id: string;
+ invited_vault_id: string;
+ status: string;
+ }>();
+ if (!relationship) return false;
+ const debt = await db.prepare(
+ "SELECT id FROM debts WHERE vault_id = ?1 LIMIT 1",
+ ).bind(invitedVaultId).first<{ id: string }>();
+ if (!debt) return false;
+ const inviterEvent = `referral-inviter:${relationship.id}`;
+ const invitedEvent = `referral-invited:${relationship.id}`;
+ await db.batch([
+ db.prepare(
+ `INSERT OR IGNORE INTO starlight_wallets
+ (vault_id, available, lifetime_earned, lifetime_sent, lifetime_received)
+ VALUES (?1, 0, 0, 0, 0)`,
+ ).bind(relationship.inviter_vault_id),
+ db.prepare(
+ `UPDATE starlight_wallets
+ SET available = available + ?1, lifetime_earned = lifetime_earned + ?1, updated_at = CURRENT_TIMESTAMP
+ WHERE vault_id = ?2 AND NOT EXISTS
+ (SELECT 1 FROM shore_value_ledger WHERE event_key = ?3)`,
+ ).bind(INVITER_STARLIGHT, relationship.inviter_vault_id, inviterEvent),
+ db.prepare(
+ `INSERT OR IGNORE INTO shore_value_ledger
+ (id, vault_id, event_key, event_type, points, reference_id)
+ VALUES (?1, ?2, ?3, 'referral_activated', ?4, ?5)`,
+ ).bind(crypto.randomUUID(), relationship.inviter_vault_id, inviterEvent, INVITER_SHORE_VALUE, relationship.id),
+ db.prepare(
+ `INSERT OR IGNORE INTO starlight_wallets
+ (vault_id, available, lifetime_earned, lifetime_sent, lifetime_received)
+ VALUES (?1, 0, 0, 0, 0)`,
+ ).bind(relationship.invited_vault_id),
+ db.prepare(
+ `UPDATE starlight_wallets
+ SET available = available + ?1, lifetime_earned = lifetime_earned + ?1, updated_at = CURRENT_TIMESTAMP
+ WHERE vault_id = ?2 AND NOT EXISTS
+ (SELECT 1 FROM shore_value_ledger WHERE event_key = ?3)`,
+ ).bind(INVITED_STARLIGHT, relationship.invited_vault_id, invitedEvent),
+ db.prepare(
+ `INSERT OR IGNORE INTO shore_value_ledger
+ (id, vault_id, event_key, event_type, points, reference_id)
+ VALUES (?1, ?2, ?3, 'referral_welcome', ?4, ?5)`,
+ ).bind(crypto.randomUUID(), relationship.invited_vault_id, invitedEvent, INVITED_SHORE_VALUE, relationship.id),
+ db.prepare(
+ `UPDATE referral_relationships
+ SET status = 'rewarded', qualified_at = COALESCE(qualified_at, CURRENT_TIMESTAMP),
+ rewarded_at = COALESCE(rewarded_at, CURRENT_TIMESTAMP)
+ WHERE id = ?1`,
+ ).bind(relationship.id),
+ ]);
+ return relationship.status !== "rewarded";
+}
diff --git a/lib/safety-policy.ts b/lib/safety-policy.ts
new file mode 100644
index 0000000..58cad19
--- /dev/null
+++ b/lib/safety-policy.ts
@@ -0,0 +1,11 @@
+export const SAFETY_POLICY_VERSION = "2026-08-01.1";
+export const COMMUNITY_POLICY_KEY = "community-rules-and-privacy";
+export const COMMUNITY_AGE_KEY = "community-age-18";
+
+export const safetySources = {
+ euPrivacyPrinciples: "https://commission.europa.eu/law/law-topic/data-protection/information-business-and-organisations/principles-gdpr_en",
+ euDataRequests: "https://commission.europa.eu/law/law-topic/data-protection/rules-business-and-organisations/dealing-individuals-requests_en",
+ californiaPrivacy: "https://oag.ca.gov/privacy/ccpa",
+ usDebtCollection: "https://www.consumerfinance.gov/consumer-tools/debt-collection/",
+ usDebtReliefRisk: "https://www.consumerfinance.gov/ask-cfpb/what-is-a-debt-relief-program-and-how-do-i-know-if-i-should-use-one-en-1457/",
+} as const;
diff --git a/lib/shore-value-server.ts b/lib/shore-value-server.ts
new file mode 100644
index 0000000..032a4aa
--- /dev/null
+++ b/lib/shore-value-server.ts
@@ -0,0 +1,53 @@
+import { getD1 } from "@/db";
+
+export type ShoreProgress = {
+ shoreValue: number;
+ starlight: {
+ available: number;
+ lifetimeEarned: number;
+ lifetimeSent: number;
+ lifetimeReceived: number;
+ };
+ recent: Array<{
+ eventType: string;
+ points: number;
+ createdAt: string;
+ }>;
+};
+
+export async function getShoreProgress(vaultId: string): Promise {
+ const db = getD1();
+ const [score, wallet, recent] = await Promise.all([
+ db.prepare(
+ "SELECT COALESCE(SUM(points), 0) AS total FROM shore_value_ledger WHERE vault_id = ?1",
+ ).bind(vaultId).first<{ total: number }>(),
+ db.prepare(
+ `SELECT available, lifetime_earned, lifetime_sent, lifetime_received
+ FROM starlight_wallets WHERE vault_id = ?1 LIMIT 1`,
+ ).bind(vaultId).first<{
+ available: number;
+ lifetime_earned: number;
+ lifetime_sent: number;
+ lifetime_received: number;
+ }>(),
+ db.prepare(
+ `SELECT event_type, points, created_at
+ FROM shore_value_ledger WHERE vault_id = ?1
+ ORDER BY created_at DESC LIMIT 8`,
+ ).bind(vaultId).all<{ event_type: string; points: number; created_at: string }>(),
+ ]);
+ return {
+ shoreValue: Number(score?.total ?? 0),
+ starlight: {
+ available: Number(wallet?.available ?? 0),
+ lifetimeEarned: Number(wallet?.lifetime_earned ?? 0),
+ lifetimeSent: Number(wallet?.lifetime_sent ?? 0),
+ lifetimeReceived: Number(wallet?.lifetime_received ?? 0),
+ },
+ recent: recent.results.map((event) => ({
+ eventType: event.event_type,
+ points: event.points,
+ createdAt: event.created_at,
+ })),
+ };
+}
diff --git a/lib/turnstile-server.ts b/lib/turnstile-server.ts
new file mode 100644
index 0000000..5fe3e53
--- /dev/null
+++ b/lib/turnstile-server.ts
@@ -0,0 +1,93 @@
+import { env } from "cloudflare:workers";
+import { HttpError, cleanText } from "@/lib/vault-server";
+
+type TurnstileVerification = {
+ success?: boolean;
+ hostname?: string;
+ action?: string;
+ "error-codes"?: string[];
+};
+
+function runtimeValue(name: string, max = 2_048) {
+ const workerEnv = env as unknown as Record;
+ const bindingValue = cleanText(workerEnv[name], max);
+ if (bindingValue) return bindingValue;
+ try {
+ return cleanText(process.env?.[name], max);
+ } catch {
+ return "";
+ }
+}
+
+function truthy(value: string) {
+ return ["1", "true", "yes", "on"].includes(value.toLowerCase());
+}
+
+function configuredKeys() {
+ return {
+ siteKey: runtimeValue("TURNSTILE_SITE_KEY"),
+ secretKey: runtimeValue("TURNSTILE_SECRET_KEY"),
+ };
+}
+
+export function turnstilePublicState() {
+ const keys = configuredKeys();
+ const configured = Boolean(keys.siteKey && keys.secretKey);
+ return {
+ configured,
+ required: configured || truthy(runtimeValue("TURNSTILE_REQUIRED", 10)),
+ siteKey: configured ? keys.siteKey : null,
+ };
+}
+
+function requestIp(request: Request) {
+ return cleanText(
+ request.headers.get("cf-connecting-ip") ?? request.headers.get("x-forwarded-for")?.split(",")[0],
+ 80,
+ );
+}
+
+export async function verifyTurnstileToken(request: Request, token: unknown, expectedAction: string) {
+ const keys = configuredKeys();
+ const configured = Boolean(keys.siteKey && keys.secretKey);
+ const required = configured || truthy(runtimeValue("TURNSTILE_REQUIRED", 10));
+ if (!configured) {
+ if (required) throw new HttpError(503, "Human verification is still being configured. Please try again later.");
+ return;
+ }
+
+ const responseToken = cleanText(token, 2_048);
+ if (!responseToken) throw new HttpError(428, "Complete the human verification before creating an account.");
+
+ const body = new FormData();
+ body.set("secret", keys.secretKey);
+ body.set("response", responseToken);
+ body.set("idempotency_key", crypto.randomUUID());
+ const remoteIp = requestIp(request);
+ if (remoteIp) body.set("remoteip", remoteIp);
+
+ let verification: TurnstileVerification;
+ try {
+ const response = await fetch("https://challenges.cloudflare.com/turnstile/v0/siteverify", {
+ method: "POST",
+ body,
+ signal: AbortSignal.timeout(8_000),
+ });
+ if (!response.ok) throw new Error(`Siteverify returned ${response.status}`);
+ verification = await response.json() as TurnstileVerification;
+ } catch {
+ throw new HttpError(503, "Human verification is temporarily unavailable. Please try again.");
+ }
+
+ if (!verification.success || verification.action !== expectedAction) {
+ throw new HttpError(403, "Human verification did not complete. Refresh it and try again.");
+ }
+
+ const allowedHostnames = runtimeValue("TURNSTILE_HOSTNAMES", 1_000)
+ .split(",")
+ .map((hostname) => hostname.trim().toLowerCase())
+ .filter(Boolean);
+ if (allowedHostnames.length && !allowedHostnames.includes((verification.hostname ?? "").toLowerCase())) {
+ throw new HttpError(403, "Human verification came from an unexpected website.");
+ }
+}
diff --git a/lib/vault-server.ts b/lib/vault-server.ts
new file mode 100644
index 0000000..dcdd770
--- /dev/null
+++ b/lib/vault-server.ts
@@ -0,0 +1,578 @@
+import { getD1 } from "@/db";
+
+export const SESSION_COOKIE = "dw_vault";
+const ACCOUNT_SESSION_COOKIE = "dw_account";
+const RECOVERY_ALPHABET = "23456789ABCDEFGHJKLMNPQRSTUVWXYZ";
+let vaultStorageSchemaPromise: Promise | null = null;
+
+export const debtKinds = new Set([
+ "mortgage",
+ "card",
+ "education",
+ "medical",
+ "car",
+ "personal",
+ "business",
+ "bnpl",
+ "informal",
+ "other",
+]);
+
+export type VaultRow = {
+ id: string;
+ recovery_hash: string;
+ alias: string;
+ region: string;
+ pressure: string;
+ age_band: string;
+ gender: string;
+ mbti: string;
+ zodiac: string;
+ self_description: string;
+ repayment_plan: string;
+ repayment_outlook: string;
+ income_plan: string;
+ position_x: number;
+ position_y: number;
+ locale: string;
+ country_code: string;
+ country_name: string;
+ display_currency: string;
+ monthly_income: number;
+ monthly_expenses: number;
+ discovery_consent: number;
+ created_at: string;
+ updated_at: string;
+};
+
+export type DebtInput = {
+ id?: string;
+ kind?: string;
+ customLabel?: string;
+ currency?: string;
+ original?: number;
+ balance?: number;
+ monthly?: number;
+ apr?: number | null;
+ minimumPayment?: number | null;
+ paymentStatus?: string;
+ remainingMonths?: number | null;
+ dueDay?: number;
+ method?: string;
+ sharingMode?: string;
+ lastPaidAt?: string;
+ payments?: number;
+ history?: { confirmedAt?: string; cashPayment?: number; newBalance?: number; source?: string; incomeType?: string; eventDate?: string }[];
+};
+
+export function noStoreJson(body: unknown, init: ResponseInit = {}) {
+ const headers = new Headers(init.headers);
+ headers.set("Cache-Control", "no-store, private");
+ return Response.json(body, { ...init, headers });
+}
+
+export function assertSameOrigin(request: Request) {
+ const origin = request.headers.get("Origin");
+ const expected = new URL(request.url).origin;
+ if (!origin || origin !== expected) {
+ throw new HttpError(403, "Request origin could not be verified.");
+ }
+}
+
+export class HttpError extends Error {
+ constructor(
+ public status: number,
+ message: string,
+ ) {
+ super(message);
+ }
+}
+
+export function routeError(error: unknown) {
+ if (error instanceof HttpError) {
+ return noStoreJson({ error: error.message }, { status: error.status });
+ }
+ const message = error instanceof Error ? error.message : "Unexpected error";
+ if (message.includes("no such table")) {
+ return noStoreJson(
+ { error: "Cloud storage is being prepared. Please try again after the latest deployment completes." },
+ { status: 503 },
+ );
+ }
+ return noStoreJson({ error: "The vault could not be updated. Please try again." }, { status: 500 });
+}
+
+async function addMissingVaultColumn(table: string, column: string, definition: string) {
+ const db = getD1();
+ const columns = await db.prepare(`PRAGMA table_info(${table})`).all<{ name: string }>();
+ if (columns.results.some((item) => item.name === column)) return;
+ try {
+ await db.prepare(`ALTER TABLE ${table} ADD COLUMN ${column} ${definition}`).run();
+ } catch (error) {
+ const message = error instanceof Error ? error.message : String(error);
+ if (!/duplicate column/i.test(message)) throw error;
+ }
+}
+
+export async function ensureVaultStorageSchema() {
+ if (!vaultStorageSchemaPromise) {
+ vaultStorageSchemaPromise = (async () => {
+ const db = getD1();
+ await db.batch([
+ db.prepare(`CREATE TABLE IF NOT EXISTS vaults (
+ id TEXT PRIMARY KEY NOT NULL,
+ recovery_hash TEXT NOT NULL UNIQUE,
+ alias TEXT NOT NULL,
+ region TEXT NOT NULL,
+ pressure TEXT NOT NULL DEFAULT '',
+ age_band TEXT NOT NULL DEFAULT '',
+ gender TEXT NOT NULL DEFAULT '',
+ mbti TEXT NOT NULL DEFAULT '',
+ zodiac TEXT NOT NULL DEFAULT '',
+ self_description TEXT NOT NULL DEFAULT '',
+ repayment_plan TEXT NOT NULL DEFAULT '',
+ repayment_outlook TEXT NOT NULL DEFAULT '',
+ income_plan TEXT NOT NULL DEFAULT '',
+ position_x REAL NOT NULL DEFAULT 47,
+ position_y REAL NOT NULL DEFAULT 63,
+ locale TEXT NOT NULL DEFAULT 'zh',
+ country_code TEXT NOT NULL DEFAULT '',
+ country_name TEXT NOT NULL DEFAULT '',
+ display_currency TEXT NOT NULL DEFAULT 'CNY',
+ monthly_income REAL NOT NULL DEFAULT 0,
+ monthly_expenses REAL NOT NULL DEFAULT 0,
+ discovery_consent INTEGER NOT NULL DEFAULT 0,
+ created_at TEXT NOT NULL DEFAULT CURRENT_TIMESTAMP,
+ updated_at TEXT NOT NULL DEFAULT CURRENT_TIMESTAMP
+ )`),
+ db.prepare(`CREATE TABLE IF NOT EXISTS debts (
+ id TEXT PRIMARY KEY NOT NULL,
+ vault_id TEXT NOT NULL REFERENCES vaults(id) ON DELETE CASCADE,
+ kind TEXT NOT NULL,
+ custom_label TEXT,
+ currency TEXT NOT NULL,
+ original REAL NOT NULL,
+ balance REAL NOT NULL,
+ monthly REAL NOT NULL,
+ apr REAL,
+ minimum_payment REAL,
+ payment_status TEXT NOT NULL DEFAULT 'unknown',
+ remaining_months INTEGER,
+ due_day INTEGER NOT NULL,
+ method TEXT NOT NULL,
+ sharing_mode TEXT NOT NULL DEFAULT 'private',
+ last_paid_at TEXT,
+ payments INTEGER NOT NULL DEFAULT 0,
+ created_at TEXT NOT NULL DEFAULT CURRENT_TIMESTAMP,
+ updated_at TEXT NOT NULL DEFAULT CURRENT_TIMESTAMP
+ )`),
+ db.prepare(`CREATE TABLE IF NOT EXISTS payment_records (
+ id TEXT PRIMARY KEY NOT NULL,
+ vault_id TEXT NOT NULL REFERENCES vaults(id) ON DELETE CASCADE,
+ debt_id TEXT NOT NULL REFERENCES debts(id) ON DELETE CASCADE,
+ scheduled_date TEXT,
+ confirmed_at TEXT NOT NULL,
+ event_date TEXT,
+ cash_payment REAL NOT NULL,
+ new_balance REAL NOT NULL,
+ source TEXT NOT NULL DEFAULT 'self_report',
+ income_type TEXT,
+ created_at TEXT NOT NULL DEFAULT CURRENT_TIMESTAMP
+ )`),
+ db.prepare(`CREATE TABLE IF NOT EXISTS policy_acceptances (
+ id TEXT PRIMARY KEY NOT NULL,
+ vault_id TEXT NOT NULL REFERENCES vaults(id) ON DELETE CASCADE,
+ policy_key TEXT NOT NULL,
+ policy_version TEXT NOT NULL,
+ accepted_at TEXT NOT NULL DEFAULT CURRENT_TIMESTAMP
+ )`),
+ db.prepare(`CREATE TABLE IF NOT EXISTS beta_enrollments (
+ id TEXT PRIMARY KEY NOT NULL,
+ vault_id TEXT NOT NULL UNIQUE REFERENCES vaults(id) ON DELETE CASCADE,
+ invite_digest TEXT NOT NULL,
+ consent_version TEXT NOT NULL,
+ created_at TEXT NOT NULL DEFAULT CURRENT_TIMESTAMP
+ )`),
+ db.prepare(`CREATE TABLE IF NOT EXISTS beta_feedback (
+ id TEXT PRIMARY KEY NOT NULL,
+ vault_id TEXT NOT NULL REFERENCES vaults(id) ON DELETE CASCADE,
+ category TEXT NOT NULL,
+ rating INTEGER NOT NULL,
+ message TEXT NOT NULL,
+ page_path TEXT NOT NULL DEFAULT '/',
+ status TEXT NOT NULL DEFAULT 'open',
+ created_at TEXT NOT NULL DEFAULT CURRENT_TIMESTAMP,
+ resolved_at TEXT
+ )`),
+ ]);
+
+ const vaultColumns: Array<[string, string]> = [
+ ["pressure", "TEXT NOT NULL DEFAULT ''"], ["age_band", "TEXT NOT NULL DEFAULT ''"],
+ ["gender", "TEXT NOT NULL DEFAULT ''"], ["mbti", "TEXT NOT NULL DEFAULT ''"],
+ ["zodiac", "TEXT NOT NULL DEFAULT ''"], ["self_description", "TEXT NOT NULL DEFAULT ''"],
+ ["repayment_plan", "TEXT NOT NULL DEFAULT ''"], ["repayment_outlook", "TEXT NOT NULL DEFAULT ''"],
+ ["income_plan", "TEXT NOT NULL DEFAULT ''"], ["position_x", "REAL NOT NULL DEFAULT 47"],
+ ["position_y", "REAL NOT NULL DEFAULT 63"], ["locale", "TEXT NOT NULL DEFAULT 'zh'"],
+ ["country_code", "TEXT NOT NULL DEFAULT ''"], ["country_name", "TEXT NOT NULL DEFAULT ''"],
+ ["display_currency", "TEXT NOT NULL DEFAULT 'CNY'"], ["monthly_income", "REAL NOT NULL DEFAULT 0"],
+ ["monthly_expenses", "REAL NOT NULL DEFAULT 0"], ["discovery_consent", "INTEGER NOT NULL DEFAULT 0"],
+ ["created_at", "TEXT NOT NULL DEFAULT '1970-01-01 00:00:00'"],
+ ["updated_at", "TEXT NOT NULL DEFAULT '1970-01-01 00:00:00'"],
+ ];
+ for (const [column, definition] of vaultColumns) await addMissingVaultColumn("vaults", column, definition);
+
+ const debtColumns: Array<[string, string]> = [
+ ["custom_label", "TEXT"], ["apr", "REAL"], ["minimum_payment", "REAL"],
+ ["payment_status", "TEXT NOT NULL DEFAULT 'unknown'"], ["remaining_months", "INTEGER"],
+ ["sharing_mode", "TEXT NOT NULL DEFAULT 'private'"], ["last_paid_at", "TEXT"],
+ ["payments", "INTEGER NOT NULL DEFAULT 0"],
+ ["created_at", "TEXT NOT NULL DEFAULT '1970-01-01 00:00:00'"],
+ ["updated_at", "TEXT NOT NULL DEFAULT '1970-01-01 00:00:00'"],
+ ];
+ for (const [column, definition] of debtColumns) await addMissingVaultColumn("debts", column, definition);
+
+ const paymentColumns: Array<[string, string]> = [
+ ["scheduled_date", "TEXT"], ["event_date", "TEXT"], ["source", "TEXT NOT NULL DEFAULT 'self_report'"],
+ ["income_type", "TEXT"], ["created_at", "TEXT NOT NULL DEFAULT '1970-01-01 00:00:00'"],
+ ];
+ for (const [column, definition] of paymentColumns) await addMissingVaultColumn("payment_records", column, definition);
+
+ await db.batch([
+ db.prepare("CREATE INDEX IF NOT EXISTS debts_vault_id_idx ON debts(vault_id)"),
+ db.prepare("CREATE INDEX IF NOT EXISTS payments_vault_id_idx ON payment_records(vault_id)"),
+ db.prepare("CREATE INDEX IF NOT EXISTS payments_debt_id_idx ON payment_records(debt_id)"),
+ db.prepare("CREATE INDEX IF NOT EXISTS policy_acceptance_vault_idx ON policy_acceptances(vault_id)"),
+ db.prepare("CREATE INDEX IF NOT EXISTS beta_enrollments_created_idx ON beta_enrollments(created_at)"),
+ db.prepare("CREATE INDEX IF NOT EXISTS beta_feedback_vault_idx ON beta_feedback(vault_id)"),
+ db.prepare("CREATE INDEX IF NOT EXISTS beta_feedback_status_idx ON beta_feedback(status)"),
+ ]);
+ })().catch((error) => {
+ vaultStorageSchemaPromise = null;
+ throw error;
+ });
+ }
+ return vaultStorageSchemaPromise;
+}
+
+export async function ensureAccountWorld(accountId: string, locale: "zh" | "en" = "zh") {
+ await ensureVaultStorageSchema();
+ const db = getD1();
+ const linked = await db.prepare(
+ `SELECT v.* FROM account_vaults av
+ JOIN vaults v ON v.id = av.vault_id
+ WHERE av.account_id = ?1 LIMIT 1`,
+ ).bind(accountId).first();
+ if (linked) return linked;
+
+ const vaultId = `world-${accountId}`;
+ const recoveryHash = await hashRecoveryCode(`account-world:${accountId}`);
+ await db.batch([
+ db.prepare(
+ `INSERT OR IGNORE INTO vaults
+ (id, recovery_hash, alias, region, locale, display_currency, discovery_consent)
+ VALUES (?1, ?2, 'Shore Walker', 'Not shared', ?3, ?4, 1)`,
+ ).bind(vaultId, recoveryHash, locale, locale === "en" ? "USD" : "CNY"),
+ db.prepare(
+ `INSERT OR IGNORE INTO account_vaults (account_id, vault_id)
+ VALUES (?1, ?2)`,
+ ).bind(accountId, vaultId),
+ ]);
+ const created = await db.prepare("SELECT * FROM vaults WHERE id = ?1 LIMIT 1").bind(vaultId).first();
+ if (!created) throw new Error("The shared world record could not be created.");
+ return created;
+}
+
+export function cleanText(value: unknown, max: number, fallback = "") {
+ if (typeof value !== "string") return fallback;
+ return value.trim().slice(0, max);
+}
+
+export function cleanNumber(value: unknown, min: number, max: number, fallback?: number) {
+ const parsed = typeof value === "number" ? value : Number(value);
+ if (!Number.isFinite(parsed)) {
+ if (fallback !== undefined) return fallback;
+ throw new HttpError(400, "A number is missing or invalid.");
+ }
+ return Math.min(max, Math.max(min, parsed));
+}
+
+function cleanOptionalNumber(value: unknown, min: number, max: number, round = false) {
+ if (value === null || value === undefined || value === "") return null;
+ const cleaned = cleanNumber(value, min, max);
+ return round ? Math.round(cleaned) : cleaned;
+}
+
+export function validateDebt(input: DebtInput) {
+ const kind = debtKinds.has(input.kind ?? "") ? input.kind! : "other";
+ const currency = cleanText(input.currency, 8, "CNY").toUpperCase();
+ const balance = cleanNumber(input.balance, 0, 1_000_000_000_000);
+ const original = Math.max(balance, cleanNumber(input.original, 0, 1_000_000_000_000));
+ const history = Array.isArray(input.history)
+ ? input.history.slice(0, 500).map((entry) => ({
+ confirmedAt: typeof entry.confirmedAt === "string"
+ ? entry.confirmedAt.slice(0, 40)
+ : new Date().toISOString(),
+ cashPayment: cleanNumber(entry.cashPayment, 0, 1_000_000_000_000, 0),
+ newBalance: cleanNumber(entry.newBalance, 0, 1_000_000_000_000, balance),
+ source: entry.source === "prepayment" || entry.source === "lucky_income" ? entry.source : "self_report",
+ incomeType: cleanText(entry.incomeType, 40) || null,
+ eventDate: /^\d{4}-\d{2}-\d{2}$/.test(entry.eventDate ?? "")
+ ? entry.eventDate!
+ : (typeof entry.confirmedAt === "string" ? entry.confirmedAt.slice(0, 10) : new Date().toISOString().slice(0, 10)),
+ }))
+ : [];
+ return {
+ id: typeof input.id === "string" && /^[a-zA-Z0-9_-]{1,80}$/.test(input.id)
+ ? input.id
+ : crypto.randomUUID(),
+ kind,
+ customLabel: kind === "other" ? cleanText(input.customLabel, 80) || null : null,
+ currency: currency || "CNY",
+ original,
+ balance,
+ monthly: cleanNumber(input.monthly, 0, 1_000_000_000_000),
+ apr: cleanOptionalNumber(input.apr, 0, 1_000),
+ minimumPayment: cleanOptionalNumber(input.minimumPayment, 0, 1_000_000_000_000),
+ paymentStatus: input.paymentStatus === "current" || input.paymentStatus === "late" || input.paymentStatus === "collection"
+ ? input.paymentStatus
+ : "unknown",
+ remainingMonths: cleanOptionalNumber(input.remainingMonths, 1, 1_200, true),
+ dueDay: Math.round(cleanNumber(input.dueDay, 1, 31)),
+ method: cleanText(input.method, 80, "Self reported") || "Self reported",
+ sharingMode: input.sharingMode === "range" ? "range" : "private",
+ lastPaidAt: typeof input.lastPaidAt === "string" ? input.lastPaidAt.slice(0, 40) : null,
+ payments: Math.round(cleanNumber(input.payments, 0, 1_000_000, 0)),
+ history,
+ };
+}
+
+export function normalizeRecoveryCode(value: unknown) {
+ if (typeof value !== "string") return "";
+ return value.toUpperCase().replace(/[^A-Z2-9]/g, "");
+}
+
+export function generateRecoveryCode() {
+ const bytes = crypto.getRandomValues(new Uint8Array(24));
+ const raw = `DW${Array.from(bytes, (byte) => RECOVERY_ALPHABET[byte & 31]).join("")}`;
+ return {
+ raw,
+ display: `${raw.slice(0, 2)}-${raw.slice(2).match(/.{1,4}/g)?.join("-") ?? raw.slice(2)}`,
+ };
+}
+
+export async function hashRecoveryCode(code: string) {
+ const digest = await crypto.subtle.digest("SHA-256", new TextEncoder().encode(code));
+ return Array.from(new Uint8Array(digest), (byte) => byte.toString(16).padStart(2, "0")).join("");
+}
+
+function readCookie(request: Request, name: string) {
+ const source = request.headers.get("Cookie") ?? "";
+ for (const part of source.split(";")) {
+ const [key, ...rest] = part.trim().split("=");
+ if (key === name) return decodeURIComponent(rest.join("="));
+ }
+ return "";
+}
+
+export async function requireVault(request: Request) {
+ const accountToken = readCookie(request, ACCOUNT_SESSION_COOKIE);
+ if (!/^[a-f0-9]{64}$/i.test(accountToken)) throw new HttpError(401, "Sign in to continue.");
+ const tokenHash = await hashRecoveryCode(accountToken.toLowerCase());
+ const db = getD1();
+ let row = await db
+ .prepare(
+ `SELECT v.* FROM account_sessions s
+ JOIN accounts a ON a.id = s.account_id
+ JOIN account_vaults av ON av.account_id = a.id
+ JOIN vaults v ON v.id = av.vault_id
+ WHERE s.token_hash = ?1 AND datetime(s.expires_at) > datetime('now') AND a.status = 'active'
+ LIMIT 1`,
+ )
+ .bind(tokenHash)
+ .first();
+ if (!row) {
+ const account = await db.prepare(
+ `SELECT a.id FROM account_sessions s JOIN accounts a ON a.id = s.account_id
+ WHERE s.token_hash = ?1 AND datetime(s.expires_at) > datetime('now') AND a.status = 'active'
+ LIMIT 1`,
+ ).bind(tokenHash).first<{ id: string }>();
+ if (!account) throw new HttpError(401, "Sign in to continue.");
+ await ensureAccountWorld(account.id);
+ row = await db.prepare(
+ `SELECT v.* FROM account_vaults av JOIN vaults v ON v.id = av.vault_id
+ WHERE av.account_id = ?1 LIMIT 1`,
+ ).bind(account.id).first();
+ }
+ if (!row) throw new HttpError(503, "The shared world is still opening. Please try again.");
+ return row;
+}
+
+export function withSessionCookie(response: Response, request: Request, rawCode: string) {
+ const secure = new URL(request.url).protocol === "https:" ? "; Secure" : "";
+ response.headers.append(
+ "Set-Cookie",
+ `${SESSION_COOKIE}=${encodeURIComponent(rawCode)}; Path=/; HttpOnly; SameSite=Lax; Max-Age=31536000${secure}`,
+ );
+ return response;
+}
+
+export function clearSessionCookie(response: Response, request: Request) {
+ const secure = new URL(request.url).protocol === "https:" ? "; Secure" : "";
+ response.headers.append(
+ "Set-Cookie",
+ `${SESSION_COOKIE}=; Path=/; HttpOnly; SameSite=Lax; Max-Age=0${secure}`,
+ );
+ return response;
+}
+
+export async function loadVaultState(vault: VaultRow) {
+ await ensureVaultStorageSchema();
+ const db = getD1();
+ const [debtsResult, paymentsResult, policyResult, betaEnrollment, betaFeedbackResult] = await Promise.all([
+ db
+ .prepare("SELECT * FROM debts WHERE vault_id = ?1 ORDER BY created_at ASC")
+ .bind(vault.id)
+ .all<{
+ id: string;
+ kind: string;
+ custom_label: string | null;
+ currency: string;
+ original: number;
+ balance: number;
+ monthly: number;
+ apr: number | null;
+ minimum_payment: number | null;
+ payment_status: string;
+ remaining_months: number | null;
+ due_day: number;
+ method: string;
+ sharing_mode: string;
+ last_paid_at: string | null;
+ payments: number;
+ }>(),
+ db
+ .prepare("SELECT * FROM payment_records WHERE vault_id = ?1 ORDER BY confirmed_at ASC")
+ .bind(vault.id)
+ .all<{
+ id: string;
+ debt_id: string;
+ scheduled_date: string | null;
+ confirmed_at: string;
+ event_date: string | null;
+ cash_payment: number;
+ new_balance: number;
+ source: string;
+ income_type: string | null;
+ }>(),
+ db
+ .prepare("SELECT policy_key, policy_version, accepted_at FROM policy_acceptances WHERE vault_id = ?1 ORDER BY accepted_at ASC")
+ .bind(vault.id)
+ .all<{ policy_key: string; policy_version: string; accepted_at: string }>(),
+ db
+ .prepare("SELECT consent_version, created_at FROM beta_enrollments WHERE vault_id = ?1 LIMIT 1")
+ .bind(vault.id)
+ .first<{ consent_version: string; created_at: string }>(),
+ db
+ .prepare("SELECT category, rating, message, page_path, status, created_at FROM beta_feedback WHERE vault_id = ?1 ORDER BY created_at ASC")
+ .bind(vault.id)
+ .all<{ category: string; rating: number; message: string; page_path: string; status: string; created_at: string }>(),
+ ]);
+
+ const paymentMap = new Map();
+ for (const payment of paymentsResult.results) {
+ const history = paymentMap.get(payment.debt_id) ?? [];
+ history.push({
+ confirmedAt: payment.confirmed_at,
+ cashPayment: payment.cash_payment,
+ newBalance: payment.new_balance,
+ source: payment.source === "prepayment" || payment.source === "lucky_income" ? payment.source : "self_report",
+ incomeType: payment.income_type ?? undefined,
+ eventDate: payment.event_date ?? undefined,
+ });
+ paymentMap.set(payment.debt_id, history);
+ }
+
+ return {
+ profile: {
+ alias: vault.alias,
+ region: vault.region,
+ pressure: vault.pressure,
+ ageBand: vault.age_band,
+ gender: vault.gender,
+ mbti: vault.mbti,
+ zodiac: vault.zodiac,
+ selfDescription: vault.self_description,
+ repaymentPlan: vault.repayment_plan,
+ repaymentOutlook: vault.repayment_outlook,
+ incomePlan: vault.income_plan,
+ countryCode: vault.country_code,
+ countryName: vault.country_name,
+ displayCurrency: vault.display_currency,
+ monthlyIncome: vault.monthly_income,
+ monthlyExpenses: vault.monthly_expenses,
+ },
+ position: {
+ x: vault.position_x,
+ y: vault.position_y,
+ },
+ locale: vault.locale,
+ discoveryConsent: Boolean(vault.discovery_consent),
+ debts: debtsResult.results.map((debt: {
+ id: string;
+ kind: string;
+ custom_label: string | null;
+ currency: string;
+ original: number;
+ balance: number;
+ monthly: number;
+ apr: number | null;
+ minimum_payment: number | null;
+ payment_status: string;
+ remaining_months: number | null;
+ due_day: number;
+ method: string;
+ sharing_mode: string;
+ last_paid_at: string | null;
+ payments: number;
+ }) => ({
+ id: debt.id,
+ kind: debt.kind,
+ customLabel: debt.custom_label ?? undefined,
+ currency: debt.currency,
+ original: debt.original,
+ balance: debt.balance,
+ monthly: debt.monthly,
+ apr: debt.apr,
+ minimumPayment: debt.minimum_payment,
+ paymentStatus: debt.payment_status === "current" || debt.payment_status === "late" || debt.payment_status === "collection"
+ ? debt.payment_status
+ : "unknown",
+ remainingMonths: debt.remaining_months,
+ dueDay: debt.due_day,
+ method: debt.method,
+ sharingMode: debt.sharing_mode === "range" ? "range" : "private",
+ lastPaidAt: debt.last_paid_at ?? undefined,
+ payments: debt.payments,
+ history: paymentMap.get(debt.id) ?? [],
+ })),
+ policyAcceptances: policyResult.results.map((acceptance) => ({
+ policyKey: acceptance.policy_key,
+ policyVersion: acceptance.policy_version,
+ acceptedAt: acceptance.accepted_at,
+ })),
+ betaEnrollment: betaEnrollment ? {
+ consentVersion: betaEnrollment.consent_version,
+ createdAt: betaEnrollment.created_at,
+ } : null,
+ betaFeedback: betaFeedbackResult.results.map((item) => ({
+ category: item.category,
+ rating: item.rating,
+ message: item.message,
+ pagePath: item.page_path,
+ status: item.status,
+ createdAt: item.created_at,
+ })),
+ createdAt: vault.created_at,
+ updatedAt: vault.updated_at,
+ };
+}
diff --git a/next.config.ts b/next.config.ts
new file mode 100644
index 0000000..e9ffa30
--- /dev/null
+++ b/next.config.ts
@@ -0,0 +1,7 @@
+import type { NextConfig } from "next";
+
+const nextConfig: NextConfig = {
+ /* config options here */
+};
+
+export default nextConfig;
diff --git a/package-lock.json b/package-lock.json
new file mode 100644
index 0000000..d898ace
--- /dev/null
+++ b/package-lock.json
@@ -0,0 +1,11216 @@
+{
+ "name": "site-creator-vinext-starter",
+ "version": "0.1.0",
+ "lockfileVersion": 3,
+ "requires": true,
+ "packages": {
+ "": {
+ "name": "site-creator-vinext-starter",
+ "version": "0.1.0",
+ "dependencies": {
+ "drizzle-orm": "0.45.2",
+ "next": "16.2.12",
+ "react": "19.2.6",
+ "react-dom": "19.2.6"
+ },
+ "devDependencies": {
+ "@cloudflare/vite-plugin": "1.37.1",
+ "@tailwindcss/postcss": "4.2.1",
+ "@types/node": "22.19.19",
+ "@types/react": "19.2.14",
+ "@types/react-dom": "19.2.3",
+ "@vitejs/plugin-react": "6.0.2",
+ "@vitejs/plugin-rsc": "0.5.26",
+ "drizzle-kit": "0.31.10",
+ "eslint": "9.39.4",
+ "eslint-config-next": "16.2.12",
+ "react-server-dom-webpack": "19.2.6",
+ "tailwindcss": "4.2.1",
+ "typescript": "5.9.3",
+ "vinext": "0.0.50",
+ "vite": "8.0.13",
+ "wrangler": "4.92.0"
+ },
+ "engines": {
+ "node": ">=22.13.0"
+ }
+ },
+ "node_modules/@alloc/quick-lru": {
+ "version": "5.2.0",
+ "resolved": "https://registry.npmjs.org/@alloc/quick-lru/-/quick-lru-5.2.0.tgz",
+ "integrity": "sha512-UrcABB+4bUrFABwbluTIBErXwvbsU/V7TZWfmbgJfbkwiBuziS9gxdODUyuiecfdGQ85jglMW6juS3+z5TsKLw==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=10"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/@babel/code-frame": {
+ "version": "7.29.0",
+ "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.29.0.tgz",
+ "integrity": "sha512-9NhCeYjq9+3uxgdtp20LSiJXJvN0FeCtNGpJxuMFZ1Kv3cWUNb6DOhJwUvcVCzKGR66cw4njwM6hrJLqgOwbcw==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@babel/helper-validator-identifier": "^7.28.5",
+ "js-tokens": "^4.0.0",
+ "picocolors": "^1.1.1"
+ },
+ "engines": {
+ "node": ">=6.9.0"
+ }
+ },
+ "node_modules/@babel/compat-data": {
+ "version": "7.29.3",
+ "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.29.3.tgz",
+ "integrity": "sha512-LIVqM46zQWZhj17qA8wb4nW/ixr2y1Nw+r1etiAWgRM6U1IqP+LNhL1yg440jYZR72jCWcWbLWzIosH+uP1fqg==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=6.9.0"
+ }
+ },
+ "node_modules/@babel/core": {
+ "version": "7.29.0",
+ "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.29.0.tgz",
+ "integrity": "sha512-CGOfOJqWjg2qW/Mb6zNsDm+u5vFQ8DxXfbM09z69p5Z6+mE1ikP2jUXw+j42Pf1XTYED2Rni5f95npYeuwMDQA==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@babel/code-frame": "^7.29.0",
+ "@babel/generator": "^7.29.0",
+ "@babel/helper-compilation-targets": "^7.28.6",
+ "@babel/helper-module-transforms": "^7.28.6",
+ "@babel/helpers": "^7.28.6",
+ "@babel/parser": "^7.29.0",
+ "@babel/template": "^7.28.6",
+ "@babel/traverse": "^7.29.0",
+ "@babel/types": "^7.29.0",
+ "@jridgewell/remapping": "^2.3.5",
+ "convert-source-map": "^2.0.0",
+ "debug": "^4.1.0",
+ "gensync": "^1.0.0-beta.2",
+ "json5": "^2.2.3",
+ "semver": "^6.3.1"
+ },
+ "engines": {
+ "node": ">=6.9.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/babel"
+ }
+ },
+ "node_modules/@babel/generator": {
+ "version": "7.29.1",
+ "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.29.1.tgz",
+ "integrity": "sha512-qsaF+9Qcm2Qv8SRIMMscAvG4O3lJ0F1GuMo5HR/Bp02LopNgnZBC/EkbevHFeGs4ls/oPz9v+Bsmzbkbe+0dUw==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@babel/parser": "^7.29.0",
+ "@babel/types": "^7.29.0",
+ "@jridgewell/gen-mapping": "^0.3.12",
+ "@jridgewell/trace-mapping": "^0.3.28",
+ "jsesc": "^3.0.2"
+ },
+ "engines": {
+ "node": ">=6.9.0"
+ }
+ },
+ "node_modules/@babel/helper-compilation-targets": {
+ "version": "7.28.6",
+ "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.28.6.tgz",
+ "integrity": "sha512-JYtls3hqi15fcx5GaSNL7SCTJ2MNmjrkHXg4FSpOA/grxK8KwyZ5bubHsCq8FXCkua6xhuaaBit+3b7+VZRfcA==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@babel/compat-data": "^7.28.6",
+ "@babel/helper-validator-option": "^7.27.1",
+ "browserslist": "^4.24.0",
+ "lru-cache": "^5.1.1",
+ "semver": "^6.3.1"
+ },
+ "engines": {
+ "node": ">=6.9.0"
+ }
+ },
+ "node_modules/@babel/helper-globals": {
+ "version": "7.28.0",
+ "resolved": "https://registry.npmjs.org/@babel/helper-globals/-/helper-globals-7.28.0.tgz",
+ "integrity": "sha512-+W6cISkXFa1jXsDEdYA8HeevQT/FULhxzR99pxphltZcVaugps53THCeiWA8SguxxpSp3gKPiuYfSWopkLQ4hw==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=6.9.0"
+ }
+ },
+ "node_modules/@babel/helper-module-imports": {
+ "version": "7.28.6",
+ "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.28.6.tgz",
+ "integrity": "sha512-l5XkZK7r7wa9LucGw9LwZyyCUscb4x37JWTPz7swwFE/0FMQAGpiWUZn8u9DzkSBWEcK25jmvubfpw2dnAMdbw==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@babel/traverse": "^7.28.6",
+ "@babel/types": "^7.28.6"
+ },
+ "engines": {
+ "node": ">=6.9.0"
+ }
+ },
+ "node_modules/@babel/helper-module-transforms": {
+ "version": "7.28.6",
+ "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.28.6.tgz",
+ "integrity": "sha512-67oXFAYr2cDLDVGLXTEABjdBJZ6drElUSI7WKp70NrpyISso3plG9SAGEF6y7zbha/wOzUByWWTJvEDVNIUGcA==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@babel/helper-module-imports": "^7.28.6",
+ "@babel/helper-validator-identifier": "^7.28.5",
+ "@babel/traverse": "^7.28.6"
+ },
+ "engines": {
+ "node": ">=6.9.0"
+ },
+ "peerDependencies": {
+ "@babel/core": "^7.0.0"
+ }
+ },
+ "node_modules/@babel/helper-string-parser": {
+ "version": "7.27.1",
+ "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.27.1.tgz",
+ "integrity": "sha512-qMlSxKbpRlAridDExk92nSobyDdpPijUq2DW6oDnUqd0iOGxmQjyqhMIihI9+zv4LPyZdRje2cavWPbCbWm3eA==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=6.9.0"
+ }
+ },
+ "node_modules/@babel/helper-validator-identifier": {
+ "version": "7.28.5",
+ "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.28.5.tgz",
+ "integrity": "sha512-qSs4ifwzKJSV39ucNjsvc6WVHs6b7S03sOh2OcHF9UHfVPqWWALUsNUVzhSBiItjRZoLHx7nIarVjqKVusUZ1Q==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=6.9.0"
+ }
+ },
+ "node_modules/@babel/helper-validator-option": {
+ "version": "7.27.1",
+ "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.27.1.tgz",
+ "integrity": "sha512-YvjJow9FxbhFFKDSuFnVCe2WxXk1zWc22fFePVNEaWJEu8IrZVlda6N0uHwzZrUM1il7NC9Mlp4MaJYbYd9JSg==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=6.9.0"
+ }
+ },
+ "node_modules/@babel/helpers": {
+ "version": "7.29.2",
+ "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.29.2.tgz",
+ "integrity": "sha512-HoGuUs4sCZNezVEKdVcwqmZN8GoHirLUcLaYVNBK2J0DadGtdcqgr3BCbvH8+XUo4NGjNl3VOtSjEKNzqfFgKw==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@babel/template": "^7.28.6",
+ "@babel/types": "^7.29.0"
+ },
+ "engines": {
+ "node": ">=6.9.0"
+ }
+ },
+ "node_modules/@babel/parser": {
+ "version": "7.29.3",
+ "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.29.3.tgz",
+ "integrity": "sha512-b3ctpQwp+PROvU/cttc4OYl4MzfJUWy6FZg+PMXfzmt/+39iHVF0sDfqay8TQM3JA2EUOyKcFZt75jWriQijsA==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@babel/types": "^7.29.0"
+ },
+ "bin": {
+ "parser": "bin/babel-parser.js"
+ },
+ "engines": {
+ "node": ">=6.0.0"
+ }
+ },
+ "node_modules/@babel/template": {
+ "version": "7.28.6",
+ "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.28.6.tgz",
+ "integrity": "sha512-YA6Ma2KsCdGb+WC6UpBVFJGXL58MDA6oyONbjyF/+5sBgxY/dwkhLogbMT2GXXyU84/IhRw/2D1Os1B/giz+BQ==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@babel/code-frame": "^7.28.6",
+ "@babel/parser": "^7.28.6",
+ "@babel/types": "^7.28.6"
+ },
+ "engines": {
+ "node": ">=6.9.0"
+ }
+ },
+ "node_modules/@babel/traverse": {
+ "version": "7.29.0",
+ "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.29.0.tgz",
+ "integrity": "sha512-4HPiQr0X7+waHfyXPZpWPfWL/J7dcN1mx9gL6WdQVMbPnF3+ZhSMs8tCxN7oHddJE9fhNE7+lxdnlyemKfJRuA==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@babel/code-frame": "^7.29.0",
+ "@babel/generator": "^7.29.0",
+ "@babel/helper-globals": "^7.28.0",
+ "@babel/parser": "^7.29.0",
+ "@babel/template": "^7.28.6",
+ "@babel/types": "^7.29.0",
+ "debug": "^4.3.1"
+ },
+ "engines": {
+ "node": ">=6.9.0"
+ }
+ },
+ "node_modules/@babel/types": {
+ "version": "7.29.0",
+ "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.29.0.tgz",
+ "integrity": "sha512-LwdZHpScM4Qz8Xw2iKSzS+cfglZzJGvofQICy7W7v4caru4EaAmyUuO6BGrbyQ2mYV11W0U8j5mBhd14dd3B0A==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@babel/helper-string-parser": "^7.27.1",
+ "@babel/helper-validator-identifier": "^7.28.5"
+ },
+ "engines": {
+ "node": ">=6.9.0"
+ }
+ },
+ "node_modules/@cloudflare/kv-asset-handler": {
+ "version": "0.5.0",
+ "resolved": "https://registry.npmjs.org/@cloudflare/kv-asset-handler/-/kv-asset-handler-0.5.0.tgz",
+ "integrity": "sha512-jxQYkj8dSIzc0cD6cMMNdOc1UVjqSqu8BZdor5s8cGjW2I8BjODt/kWPVdY+u9zj3ms75Q5qaZgnxUad83+eAg==",
+ "dev": true,
+ "license": "MIT OR Apache-2.0",
+ "engines": {
+ "node": ">=22.0.0"
+ }
+ },
+ "node_modules/@cloudflare/unenv-preset": {
+ "version": "2.16.1",
+ "resolved": "https://registry.npmjs.org/@cloudflare/unenv-preset/-/unenv-preset-2.16.1.tgz",
+ "integrity": "sha512-ECxObrMfyTl5bhQf/lZCXwo5G6xX9IAUo+nDMKK4SZ8m4Jvvxp52vilxyySSWh2YTZz8+HQ07qGH/2rEom1vDw==",
+ "dev": true,
+ "license": "MIT OR Apache-2.0",
+ "peerDependencies": {
+ "unenv": "2.0.0-rc.24",
+ "workerd": ">1.20260305.0 <2.0.0-0"
+ },
+ "peerDependenciesMeta": {
+ "workerd": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/@cloudflare/vite-plugin": {
+ "version": "1.37.1",
+ "resolved": "https://registry.npmjs.org/@cloudflare/vite-plugin/-/vite-plugin-1.37.1.tgz",
+ "integrity": "sha512-FldhsmkXyLsX3yI+p0aJDo/kGyY69pDdynz2JjcuH3eCiQ+G9XaY3CrN+UYEfCbWv8CiR2wL95lNg0fT/HfwWA==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@cloudflare/unenv-preset": "2.16.1",
+ "miniflare": "4.20260515.0",
+ "unenv": "2.0.0-rc.24",
+ "wrangler": "4.92.0",
+ "ws": "8.18.0"
+ },
+ "peerDependencies": {
+ "vite": "^6.1.0 || ^7.0.0 || ^8.0.0",
+ "wrangler": "^4.92.0"
+ }
+ },
+ "node_modules/@cloudflare/workerd-darwin-64": {
+ "version": "1.20260515.1",
+ "resolved": "https://registry.npmjs.org/@cloudflare/workerd-darwin-64/-/workerd-darwin-64-1.20260515.1.tgz",
+ "integrity": "sha512-Wtw44el2pNbzixvTkWdfeBDTrQwQbJRz7/JUvPKV27I0pQWXbhNJPpM8cstq/pbrU5AGcA/HjFH6yPMRTIRKig==",
+ "cpu": [
+ "x64"
+ ],
+ "dev": true,
+ "license": "Apache-2.0",
+ "optional": true,
+ "os": [
+ "darwin"
+ ],
+ "engines": {
+ "node": ">=16"
+ }
+ },
+ "node_modules/@cloudflare/workerd-darwin-arm64": {
+ "version": "1.20260515.1",
+ "resolved": "https://registry.npmjs.org/@cloudflare/workerd-darwin-arm64/-/workerd-darwin-arm64-1.20260515.1.tgz",
+ "integrity": "sha512-X8EqkZej6FfmhF9AVAQ3FhyQRr9acS4RcDunMU2YiuxKHF1IU8zzH3vY30/POaG+rUu9vGDp/VgUl49VPenHJQ==",
+ "cpu": [
+ "arm64"
+ ],
+ "dev": true,
+ "license": "Apache-2.0",
+ "optional": true,
+ "os": [
+ "darwin"
+ ],
+ "engines": {
+ "node": ">=16"
+ }
+ },
+ "node_modules/@cloudflare/workerd-linux-64": {
+ "version": "1.20260515.1",
+ "resolved": "https://registry.npmjs.org/@cloudflare/workerd-linux-64/-/workerd-linux-64-1.20260515.1.tgz",
+ "integrity": "sha512-CDC89QxQ7Y7t7RG1Jd9vj/qolE1sQRkI2OSEuV5BMJi0vW/gV4OVG6xjpdK3b1OYnSWDzF7NpvlR5Yg86q7k4g==",
+ "cpu": [
+ "x64"
+ ],
+ "dev": true,
+ "license": "Apache-2.0",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">=16"
+ }
+ },
+ "node_modules/@cloudflare/workerd-linux-arm64": {
+ "version": "1.20260515.1",
+ "resolved": "https://registry.npmjs.org/@cloudflare/workerd-linux-arm64/-/workerd-linux-arm64-1.20260515.1.tgz",
+ "integrity": "sha512-WxbW/PToYES4fvHXzsr/5qOiETQs/Z9iZ0mjSZAiEwq5cMLZemzGN0COx+uFb9OvQwzh6Pg159qPFnw3+i9FuA==",
+ "cpu": [
+ "arm64"
+ ],
+ "dev": true,
+ "license": "Apache-2.0",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">=16"
+ }
+ },
+ "node_modules/@cloudflare/workerd-windows-64": {
+ "version": "1.20260515.1",
+ "resolved": "https://registry.npmjs.org/@cloudflare/workerd-windows-64/-/workerd-windows-64-1.20260515.1.tgz",
+ "integrity": "sha512-WmV/iv+MHjYsvkcMVzpM2B5/mf06UUkdpVhZrtMfV9graWjBGPYFvE/eab8748RPVGKh1Xe1vXofLzDSwc08lA==",
+ "cpu": [
+ "x64"
+ ],
+ "dev": true,
+ "license": "Apache-2.0",
+ "optional": true,
+ "os": [
+ "win32"
+ ],
+ "engines": {
+ "node": ">=16"
+ }
+ },
+ "node_modules/@cspotcode/source-map-support": {
+ "version": "0.8.1",
+ "resolved": "https://registry.npmjs.org/@cspotcode/source-map-support/-/source-map-support-0.8.1.tgz",
+ "integrity": "sha512-IchNf6dN4tHoMFIn/7OE8LWZ19Y6q/67Bmf6vnGREv8RSbBVb9LPJxEcnwrcwX6ixSvaiGoomAUvu4YSxXrVgw==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@jridgewell/trace-mapping": "0.3.9"
+ },
+ "engines": {
+ "node": ">=12"
+ }
+ },
+ "node_modules/@cspotcode/source-map-support/node_modules/@jridgewell/trace-mapping": {
+ "version": "0.3.9",
+ "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.9.tgz",
+ "integrity": "sha512-3Belt6tdc8bPgAtbcmdtNJlirVoTmEb5e2gC94PnkwEW9jI6CAHUeoG85tjWP5WquqfavoMtMwiG4P926ZKKuQ==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@jridgewell/resolve-uri": "^3.0.3",
+ "@jridgewell/sourcemap-codec": "^1.4.10"
+ }
+ },
+ "node_modules/@drizzle-team/brocli": {
+ "version": "0.10.2",
+ "resolved": "https://registry.npmjs.org/@drizzle-team/brocli/-/brocli-0.10.2.tgz",
+ "integrity": "sha512-z33Il7l5dKjUgGULTqBsQBQwckHh5AbIuxhdsIxDDiZAzBOrZO6q9ogcWC65kU382AfynTfgNumVcNIjuIua6w==",
+ "dev": true,
+ "license": "Apache-2.0"
+ },
+ "node_modules/@emnapi/core": {
+ "version": "1.11.3",
+ "resolved": "https://registry.npmjs.org/@emnapi/core/-/core-1.11.3.tgz",
+ "integrity": "sha512-zLpS5asjEb7lq8jYLq37N6XKaE41DIexlY1rF/z4/tIl3wo13Sqm28fRyfIsKZD+NZ8mM5RoKkpW/rBcuoSZSg==",
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "dependencies": {
+ "@emnapi/wasi-threads": "1.2.3",
+ "tslib": "^2.4.0"
+ }
+ },
+ "node_modules/@emnapi/runtime": {
+ "version": "1.11.3",
+ "resolved": "https://registry.npmjs.org/@emnapi/runtime/-/runtime-1.11.3.tgz",
+ "integrity": "sha512-Xz4Tpyki7XyrpbUK1jR1AhdAdaXyhhY4lZ3neLodmhpuWfy2PAQN5B46sAiU4liOXGLkHypn/qU+jvfWSCYYLA==",
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "dependencies": {
+ "tslib": "^2.4.0"
+ }
+ },
+ "node_modules/@emnapi/wasi-threads": {
+ "version": "1.2.3",
+ "resolved": "https://registry.npmjs.org/@emnapi/wasi-threads/-/wasi-threads-1.2.3.tgz",
+ "integrity": "sha512-ELEBe8PsLvvJ6QMr0zLt8ffvOHW/dc1m3CEzNMg7aJUv3bMaoDtw2TXyDAwkYBuroxxuHEwhRTLJSe5sya547g==",
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "dependencies": {
+ "tslib": "^2.4.0"
+ }
+ },
+ "node_modules/@esbuild-kit/core-utils": {
+ "version": "3.3.2",
+ "resolved": "https://registry.npmjs.org/@esbuild-kit/core-utils/-/core-utils-3.3.2.tgz",
+ "integrity": "sha512-sPRAnw9CdSsRmEtnsl2WXWdyquogVpB3yZ3dgwJfe8zrOzTsV7cJvmwrKVa+0ma5BoiGJ+BoqkMvawbayKUsqQ==",
+ "deprecated": "Merged into tsx: https://tsx.is",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "esbuild": "~0.18.20",
+ "source-map-support": "^0.5.21"
+ }
+ },
+ "node_modules/@esbuild-kit/core-utils/node_modules/@esbuild/android-arm": {
+ "version": "0.18.20",
+ "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.18.20.tgz",
+ "integrity": "sha512-fyi7TDI/ijKKNZTUJAQqiG5T7YjJXgnzkURqmGj13C6dCqckZBLdl4h7bkhHt/t0WP+zO9/zwroDvANaOqO5Sw==",
+ "cpu": [
+ "arm"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "android"
+ ],
+ "engines": {
+ "node": ">=12"
+ }
+ },
+ "node_modules/@esbuild-kit/core-utils/node_modules/@esbuild/android-arm64": {
+ "version": "0.18.20",
+ "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.18.20.tgz",
+ "integrity": "sha512-Nz4rJcchGDtENV0eMKUNa6L12zz2zBDXuhj/Vjh18zGqB44Bi7MBMSXjgunJgjRhCmKOjnPuZp4Mb6OKqtMHLQ==",
+ "cpu": [
+ "arm64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "android"
+ ],
+ "engines": {
+ "node": ">=12"
+ }
+ },
+ "node_modules/@esbuild-kit/core-utils/node_modules/@esbuild/android-x64": {
+ "version": "0.18.20",
+ "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.18.20.tgz",
+ "integrity": "sha512-8GDdlePJA8D6zlZYJV/jnrRAi6rOiNaCC/JclcXpB+KIuvfBN4owLtgzY2bsxnx666XjJx2kDPUmnTtR8qKQUg==",
+ "cpu": [
+ "x64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "android"
+ ],
+ "engines": {
+ "node": ">=12"
+ }
+ },
+ "node_modules/@esbuild-kit/core-utils/node_modules/@esbuild/darwin-arm64": {
+ "version": "0.18.20",
+ "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.18.20.tgz",
+ "integrity": "sha512-bxRHW5kHU38zS2lPTPOyuyTm+S+eobPUnTNkdJEfAddYgEcll4xkT8DB9d2008DtTbl7uJag2HuE5NZAZgnNEA==",
+ "cpu": [
+ "arm64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "darwin"
+ ],
+ "engines": {
+ "node": ">=12"
+ }
+ },
+ "node_modules/@esbuild-kit/core-utils/node_modules/@esbuild/darwin-x64": {
+ "version": "0.18.20",
+ "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.18.20.tgz",
+ "integrity": "sha512-pc5gxlMDxzm513qPGbCbDukOdsGtKhfxD1zJKXjCCcU7ju50O7MeAZ8c4krSJcOIJGFR+qx21yMMVYwiQvyTyQ==",
+ "cpu": [
+ "x64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "darwin"
+ ],
+ "engines": {
+ "node": ">=12"
+ }
+ },
+ "node_modules/@esbuild-kit/core-utils/node_modules/@esbuild/freebsd-arm64": {
+ "version": "0.18.20",
+ "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.18.20.tgz",
+ "integrity": "sha512-yqDQHy4QHevpMAaxhhIwYPMv1NECwOvIpGCZkECn8w2WFHXjEwrBn3CeNIYsibZ/iZEUemj++M26W3cNR5h+Tw==",
+ "cpu": [
+ "arm64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "freebsd"
+ ],
+ "engines": {
+ "node": ">=12"
+ }
+ },
+ "node_modules/@esbuild-kit/core-utils/node_modules/@esbuild/freebsd-x64": {
+ "version": "0.18.20",
+ "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.18.20.tgz",
+ "integrity": "sha512-tgWRPPuQsd3RmBZwarGVHZQvtzfEBOreNuxEMKFcd5DaDn2PbBxfwLcj4+aenoh7ctXcbXmOQIn8HI6mCSw5MQ==",
+ "cpu": [
+ "x64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "freebsd"
+ ],
+ "engines": {
+ "node": ">=12"
+ }
+ },
+ "node_modules/@esbuild-kit/core-utils/node_modules/@esbuild/linux-arm": {
+ "version": "0.18.20",
+ "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.18.20.tgz",
+ "integrity": "sha512-/5bHkMWnq1EgKr1V+Ybz3s1hWXok7mDFUMQ4cG10AfW3wL02PSZi5kFpYKrptDsgb2WAJIvRcDm+qIvXf/apvg==",
+ "cpu": [
+ "arm"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">=12"
+ }
+ },
+ "node_modules/@esbuild-kit/core-utils/node_modules/@esbuild/linux-arm64": {
+ "version": "0.18.20",
+ "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.18.20.tgz",
+ "integrity": "sha512-2YbscF+UL7SQAVIpnWvYwM+3LskyDmPhe31pE7/aoTMFKKzIc9lLbyGUpmmb8a8AixOL61sQ/mFh3jEjHYFvdA==",
+ "cpu": [
+ "arm64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">=12"
+ }
+ },
+ "node_modules/@esbuild-kit/core-utils/node_modules/@esbuild/linux-ia32": {
+ "version": "0.18.20",
+ "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.18.20.tgz",
+ "integrity": "sha512-P4etWwq6IsReT0E1KHU40bOnzMHoH73aXp96Fs8TIT6z9Hu8G6+0SHSw9i2isWrD2nbx2qo5yUqACgdfVGx7TA==",
+ "cpu": [
+ "ia32"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">=12"
+ }
+ },
+ "node_modules/@esbuild-kit/core-utils/node_modules/@esbuild/linux-loong64": {
+ "version": "0.18.20",
+ "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.18.20.tgz",
+ "integrity": "sha512-nXW8nqBTrOpDLPgPY9uV+/1DjxoQ7DoB2N8eocyq8I9XuqJ7BiAMDMf9n1xZM9TgW0J8zrquIb/A7s3BJv7rjg==",
+ "cpu": [
+ "loong64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">=12"
+ }
+ },
+ "node_modules/@esbuild-kit/core-utils/node_modules/@esbuild/linux-mips64el": {
+ "version": "0.18.20",
+ "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.18.20.tgz",
+ "integrity": "sha512-d5NeaXZcHp8PzYy5VnXV3VSd2D328Zb+9dEq5HE6bw6+N86JVPExrA6O68OPwobntbNJ0pzCpUFZTo3w0GyetQ==",
+ "cpu": [
+ "mips64el"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">=12"
+ }
+ },
+ "node_modules/@esbuild-kit/core-utils/node_modules/@esbuild/linux-ppc64": {
+ "version": "0.18.20",
+ "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.18.20.tgz",
+ "integrity": "sha512-WHPyeScRNcmANnLQkq6AfyXRFr5D6N2sKgkFo2FqguP44Nw2eyDlbTdZwd9GYk98DZG9QItIiTlFLHJHjxP3FA==",
+ "cpu": [
+ "ppc64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">=12"
+ }
+ },
+ "node_modules/@esbuild-kit/core-utils/node_modules/@esbuild/linux-riscv64": {
+ "version": "0.18.20",
+ "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.18.20.tgz",
+ "integrity": "sha512-WSxo6h5ecI5XH34KC7w5veNnKkju3zBRLEQNY7mv5mtBmrP/MjNBCAlsM2u5hDBlS3NGcTQpoBvRzqBcRtpq1A==",
+ "cpu": [
+ "riscv64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">=12"
+ }
+ },
+ "node_modules/@esbuild-kit/core-utils/node_modules/@esbuild/linux-s390x": {
+ "version": "0.18.20",
+ "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.18.20.tgz",
+ "integrity": "sha512-+8231GMs3mAEth6Ja1iK0a1sQ3ohfcpzpRLH8uuc5/KVDFneH6jtAJLFGafpzpMRO6DzJ6AvXKze9LfFMrIHVQ==",
+ "cpu": [
+ "s390x"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">=12"
+ }
+ },
+ "node_modules/@esbuild-kit/core-utils/node_modules/@esbuild/linux-x64": {
+ "version": "0.18.20",
+ "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.18.20.tgz",
+ "integrity": "sha512-UYqiqemphJcNsFEskc73jQ7B9jgwjWrSayxawS6UVFZGWrAAtkzjxSqnoclCXxWtfwLdzU+vTpcNYhpn43uP1w==",
+ "cpu": [
+ "x64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">=12"
+ }
+ },
+ "node_modules/@esbuild-kit/core-utils/node_modules/@esbuild/netbsd-x64": {
+ "version": "0.18.20",
+ "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.18.20.tgz",
+ "integrity": "sha512-iO1c++VP6xUBUmltHZoMtCUdPlnPGdBom6IrO4gyKPFFVBKioIImVooR5I83nTew5UOYrk3gIJhbZh8X44y06A==",
+ "cpu": [
+ "x64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "netbsd"
+ ],
+ "engines": {
+ "node": ">=12"
+ }
+ },
+ "node_modules/@esbuild-kit/core-utils/node_modules/@esbuild/openbsd-x64": {
+ "version": "0.18.20",
+ "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.18.20.tgz",
+ "integrity": "sha512-e5e4YSsuQfX4cxcygw/UCPIEP6wbIL+se3sxPdCiMbFLBWu0eiZOJ7WoD+ptCLrmjZBK1Wk7I6D/I3NglUGOxg==",
+ "cpu": [
+ "x64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "openbsd"
+ ],
+ "engines": {
+ "node": ">=12"
+ }
+ },
+ "node_modules/@esbuild-kit/core-utils/node_modules/@esbuild/sunos-x64": {
+ "version": "0.18.20",
+ "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.18.20.tgz",
+ "integrity": "sha512-kDbFRFp0YpTQVVrqUd5FTYmWo45zGaXe0X8E1G/LKFC0v8x0vWrhOWSLITcCn63lmZIxfOMXtCfti/RxN/0wnQ==",
+ "cpu": [
+ "x64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "sunos"
+ ],
+ "engines": {
+ "node": ">=12"
+ }
+ },
+ "node_modules/@esbuild-kit/core-utils/node_modules/@esbuild/win32-arm64": {
+ "version": "0.18.20",
+ "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.18.20.tgz",
+ "integrity": "sha512-ddYFR6ItYgoaq4v4JmQQaAI5s7npztfV4Ag6NrhiaW0RrnOXqBkgwZLofVTlq1daVTQNhtI5oieTvkRPfZrePg==",
+ "cpu": [
+ "arm64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "win32"
+ ],
+ "engines": {
+ "node": ">=12"
+ }
+ },
+ "node_modules/@esbuild-kit/core-utils/node_modules/@esbuild/win32-ia32": {
+ "version": "0.18.20",
+ "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.18.20.tgz",
+ "integrity": "sha512-Wv7QBi3ID/rROT08SABTS7eV4hX26sVduqDOTe1MvGMjNd3EjOz4b7zeexIR62GTIEKrfJXKL9LFxTYgkyeu7g==",
+ "cpu": [
+ "ia32"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "win32"
+ ],
+ "engines": {
+ "node": ">=12"
+ }
+ },
+ "node_modules/@esbuild-kit/core-utils/node_modules/@esbuild/win32-x64": {
+ "version": "0.18.20",
+ "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.18.20.tgz",
+ "integrity": "sha512-kTdfRcSiDfQca/y9QIkng02avJ+NCaQvrMejlsB3RRv5sE9rRoeBPISaZpKxHELzRxZyLvNts1P27W3wV+8geQ==",
+ "cpu": [
+ "x64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "win32"
+ ],
+ "engines": {
+ "node": ">=12"
+ }
+ },
+ "node_modules/@esbuild-kit/core-utils/node_modules/esbuild": {
+ "version": "0.18.20",
+ "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.18.20.tgz",
+ "integrity": "sha512-ceqxoedUrcayh7Y7ZX6NdbbDzGROiyVBgC4PriJThBKSVPWnnFHZAkfI1lJT8QFkOwH4qOS2SJkS4wvpGl8BpA==",
+ "dev": true,
+ "hasInstallScript": true,
+ "license": "MIT",
+ "bin": {
+ "esbuild": "bin/esbuild"
+ },
+ "engines": {
+ "node": ">=12"
+ },
+ "optionalDependencies": {
+ "@esbuild/android-arm": "0.18.20",
+ "@esbuild/android-arm64": "0.18.20",
+ "@esbuild/android-x64": "0.18.20",
+ "@esbuild/darwin-arm64": "0.18.20",
+ "@esbuild/darwin-x64": "0.18.20",
+ "@esbuild/freebsd-arm64": "0.18.20",
+ "@esbuild/freebsd-x64": "0.18.20",
+ "@esbuild/linux-arm": "0.18.20",
+ "@esbuild/linux-arm64": "0.18.20",
+ "@esbuild/linux-ia32": "0.18.20",
+ "@esbuild/linux-loong64": "0.18.20",
+ "@esbuild/linux-mips64el": "0.18.20",
+ "@esbuild/linux-ppc64": "0.18.20",
+ "@esbuild/linux-riscv64": "0.18.20",
+ "@esbuild/linux-s390x": "0.18.20",
+ "@esbuild/linux-x64": "0.18.20",
+ "@esbuild/netbsd-x64": "0.18.20",
+ "@esbuild/openbsd-x64": "0.18.20",
+ "@esbuild/sunos-x64": "0.18.20",
+ "@esbuild/win32-arm64": "0.18.20",
+ "@esbuild/win32-ia32": "0.18.20",
+ "@esbuild/win32-x64": "0.18.20"
+ }
+ },
+ "node_modules/@esbuild-kit/esm-loader": {
+ "version": "2.6.5",
+ "resolved": "https://registry.npmjs.org/@esbuild-kit/esm-loader/-/esm-loader-2.6.5.tgz",
+ "integrity": "sha512-FxEMIkJKnodyA1OaCUoEvbYRkoZlLZ4d/eXFu9Fh8CbBBgP5EmZxrfTRyN0qpXZ4vOvqnE5YdRdcrmUUXuU+dA==",
+ "deprecated": "Merged into tsx: https://tsx.is",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@esbuild-kit/core-utils": "^3.3.2",
+ "get-tsconfig": "^4.7.0"
+ }
+ },
+ "node_modules/@esbuild/aix-ppc64": {
+ "version": "0.28.0",
+ "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.28.0.tgz",
+ "integrity": "sha512-lhRUCeuOyJQURhTxl4WkpFTjIsbDayJHih5kZC1giwE+MhIzAb7mEsQMqMf18rHLsrb5qI1tafG20mLxEWcWlA==",
+ "cpu": [
+ "ppc64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "aix"
+ ],
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/@esbuild/android-arm": {
+ "version": "0.28.0",
+ "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.28.0.tgz",
+ "integrity": "sha512-wqh0ByljabXLKHeWXYLqoJ5jKC4XBaw6Hk08OfMrCRd2nP2ZQ5eleDZC41XHyCNgktBGYMbqnrJKq/K/lzPMSQ==",
+ "cpu": [
+ "arm"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "android"
+ ],
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/@esbuild/android-arm64": {
+ "version": "0.28.0",
+ "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.28.0.tgz",
+ "integrity": "sha512-+WzIXQOSaGs33tLEgYPYe/yQHf0WTU0X42Jca3y8NWMbUVhp7rUnw+vAsRC/QiDrdD31IszMrZy+qwPOPjd+rw==",
+ "cpu": [
+ "arm64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "android"
+ ],
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/@esbuild/android-x64": {
+ "version": "0.28.0",
+ "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.28.0.tgz",
+ "integrity": "sha512-+VJggoaKhk2VNNqVL7f6S189UzShHC/mR9EE8rDdSkdpN0KflSwWY/gWjDrNxxisg8Fp1ZCD9jLMo4m0OUfeUA==",
+ "cpu": [
+ "x64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "android"
+ ],
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/@esbuild/darwin-arm64": {
+ "version": "0.28.0",
+ "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.28.0.tgz",
+ "integrity": "sha512-0T+A9WZm+bZ84nZBtk1ckYsOvyA3x7e2Acj1KdVfV4/2tdG4fzUp91YHx+GArWLtwqp77pBXVCPn2We7Letr0Q==",
+ "cpu": [
+ "arm64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "darwin"
+ ],
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/@esbuild/darwin-x64": {
+ "version": "0.28.0",
+ "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.28.0.tgz",
+ "integrity": "sha512-fyzLm/DLDl/84OCfp2f/XQ4flmORsjU7VKt8HLjvIXChJoFFOIL6pLJPH4Yhd1n1gGFF9mPwtlN5Wf82DZs+LQ==",
+ "cpu": [
+ "x64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "darwin"
+ ],
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/@esbuild/freebsd-arm64": {
+ "version": "0.28.0",
+ "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.28.0.tgz",
+ "integrity": "sha512-l9GeW5UZBT9k9brBYI+0WDffcRxgHQD8ShN2Ur4xWq/NFzUKm3k5lsH4PdaRgb2w7mI9u61nr2gI2mLI27Nh3Q==",
+ "cpu": [
+ "arm64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "freebsd"
+ ],
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/@esbuild/freebsd-x64": {
+ "version": "0.28.0",
+ "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.28.0.tgz",
+ "integrity": "sha512-BXoQai/A0wPO6Es3yFJ7APCiKGc1tdAEOgeTNy3SsB491S3aHn4S4r3e976eUnPdU+NbdtmBuLncYir2tMU9Nw==",
+ "cpu": [
+ "x64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "freebsd"
+ ],
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/@esbuild/linux-arm": {
+ "version": "0.28.0",
+ "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.28.0.tgz",
+ "integrity": "sha512-CjaaREJagqJp7iTaNQjjidaNbCKYcd4IDkzbwwxtSvjI7NZm79qiHc8HqciMddQ6CKvJT6aBd8lO9kN/ZudLlw==",
+ "cpu": [
+ "arm"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/@esbuild/linux-arm64": {
+ "version": "0.28.0",
+ "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.28.0.tgz",
+ "integrity": "sha512-RVyzfb3FWsGA55n6WY0MEIEPURL1FcbhFE6BffZEMEekfCzCIMtB5yyDcFnVbTnwk+CLAgTujmV/Lgvih56W+A==",
+ "cpu": [
+ "arm64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/@esbuild/linux-ia32": {
+ "version": "0.28.0",
+ "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.28.0.tgz",
+ "integrity": "sha512-KBnSTt1kxl9x70q+ydterVdl+Cn0H18ngRMRCEQfrbqdUuntQQ0LoMZv47uB97NljZFzY6HcfqEZ2SAyIUTQBQ==",
+ "cpu": [
+ "ia32"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/@esbuild/linux-loong64": {
+ "version": "0.28.0",
+ "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.28.0.tgz",
+ "integrity": "sha512-zpSlUce1mnxzgBADvxKXX5sl8aYQHo2ezvMNI8I0lbblJtp8V4odlm3Yzlj7gPyt3T8ReksE6bK+pT3WD+aJRg==",
+ "cpu": [
+ "loong64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/@esbuild/linux-mips64el": {
+ "version": "0.28.0",
+ "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.28.0.tgz",
+ "integrity": "sha512-2jIfP6mmjkdmeTlsX/9vmdmhBmKADrWqN7zcdtHIeNSCH1SqIoNI63cYsjQR8J+wGa4Y5izRcSHSm8K3QWmk3w==",
+ "cpu": [
+ "mips64el"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/@esbuild/linux-ppc64": {
+ "version": "0.28.0",
+ "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.28.0.tgz",
+ "integrity": "sha512-bc0FE9wWeC0WBm49IQMPSPILRocGTQt3j5KPCA8os6VprfuJ7KD+5PzESSrJ6GmPIPJK965ZJHTUlSA6GNYEhg==",
+ "cpu": [
+ "ppc64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/@esbuild/linux-riscv64": {
+ "version": "0.28.0",
+ "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.28.0.tgz",
+ "integrity": "sha512-SQPZOwoTTT/HXFXQJG/vBX8sOFagGqvZyXcgLA3NhIqcBv1BJU1d46c0rGcrij2B56Z2rNiSLaZOYW5cUk7yLQ==",
+ "cpu": [
+ "riscv64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/@esbuild/linux-s390x": {
+ "version": "0.28.0",
+ "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.28.0.tgz",
+ "integrity": "sha512-SCfR0HN8CEEjnYnySJTd2cw0k9OHB/YFzt5zgJEwa+wL/T/raGWYMBqwDNAC6dqFKmJYZoQBRfHjgwLHGSrn3Q==",
+ "cpu": [
+ "s390x"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/@esbuild/linux-x64": {
+ "version": "0.28.0",
+ "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.28.0.tgz",
+ "integrity": "sha512-us0dSb9iFxIi8srnpl931Nvs65it/Jd2a2K3qs7fz2WfGPHqzfzZTfec7oxZJRNPXPnNYZtanmRc4AL/JwVzHQ==",
+ "cpu": [
+ "x64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/@esbuild/netbsd-arm64": {
+ "version": "0.28.0",
+ "resolved": "https://registry.npmjs.org/@esbuild/netbsd-arm64/-/netbsd-arm64-0.28.0.tgz",
+ "integrity": "sha512-CR/RYotgtCKwtftMwJlUU7xCVNg3lMYZ0RzTmAHSfLCXw3NtZtNpswLEj/Kkf6kEL3Gw+BpOekRX0BYCtklhUw==",
+ "cpu": [
+ "arm64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "netbsd"
+ ],
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/@esbuild/netbsd-x64": {
+ "version": "0.28.0",
+ "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.28.0.tgz",
+ "integrity": "sha512-nU1yhmYutL+fQ71Kxnhg8uEOdC0pwEW9entHykTgEbna2pw2dkbFSMeqjjyHZoCmt8SBkOSvV+yNmm94aUrrqw==",
+ "cpu": [
+ "x64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "netbsd"
+ ],
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/@esbuild/openbsd-arm64": {
+ "version": "0.28.0",
+ "resolved": "https://registry.npmjs.org/@esbuild/openbsd-arm64/-/openbsd-arm64-0.28.0.tgz",
+ "integrity": "sha512-cXb5vApOsRsxsEl4mcZ1XY3D4DzcoMxR/nnc4IyqYs0rTI8ZKmW6kyyg+11Z8yvgMfAEldKzP7AdP64HnSC/6g==",
+ "cpu": [
+ "arm64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "openbsd"
+ ],
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/@esbuild/openbsd-x64": {
+ "version": "0.28.0",
+ "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.28.0.tgz",
+ "integrity": "sha512-8wZM2qqtv9UP3mzy7HiGYNH/zjTA355mpeuA+859TyR+e+Tc08IHYpLJuMsfpDJwoLo1ikIJI8jC3GFjnRClzA==",
+ "cpu": [
+ "x64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "openbsd"
+ ],
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/@esbuild/openharmony-arm64": {
+ "version": "0.28.0",
+ "resolved": "https://registry.npmjs.org/@esbuild/openharmony-arm64/-/openharmony-arm64-0.28.0.tgz",
+ "integrity": "sha512-FLGfyizszcef5C3YtoyQDACyg95+dndv79i2EekILBofh5wpCa1KuBqOWKrEHZg3zrL3t5ouE5jgr94vA+Wb2w==",
+ "cpu": [
+ "arm64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "openharmony"
+ ],
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/@esbuild/sunos-x64": {
+ "version": "0.28.0",
+ "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.28.0.tgz",
+ "integrity": "sha512-1ZgjUoEdHZZl/YlV76TSCz9Hqj9h9YmMGAgAPYd+q4SicWNX3G5GCyx9uhQWSLcbvPW8Ni7lj4gDa1T40akdlw==",
+ "cpu": [
+ "x64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "sunos"
+ ],
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/@esbuild/win32-arm64": {
+ "version": "0.28.0",
+ "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.28.0.tgz",
+ "integrity": "sha512-Q9StnDmQ/enxnpxCCLSg0oo4+34B9TdXpuyPeTedN/6+iXBJ4J+zwfQI28u/Jl40nOYAxGoNi7mFP40RUtkmUA==",
+ "cpu": [
+ "arm64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "win32"
+ ],
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/@esbuild/win32-ia32": {
+ "version": "0.28.0",
+ "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.28.0.tgz",
+ "integrity": "sha512-zF3ag/gfiCe6U2iczcRzSYJKH1DCI+ByzSENHlM2FcDbEeo5Zd2C86Aq0tKUYAJJ1obRP84ymxIAksZUcdztHA==",
+ "cpu": [
+ "ia32"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "win32"
+ ],
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/@esbuild/win32-x64": {
+ "version": "0.28.0",
+ "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.28.0.tgz",
+ "integrity": "sha512-pEl1bO9mfAmIC+tW5btTmrKaujg3zGtUmWNdCw/xs70FBjwAL3o9OEKNHvNmnyylD6ubxUERiEhdsL0xBQ9efw==",
+ "cpu": [
+ "x64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "win32"
+ ],
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/@eslint-community/eslint-utils": {
+ "version": "4.9.1",
+ "resolved": "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.9.1.tgz",
+ "integrity": "sha512-phrYmNiYppR7znFEdqgfWHXR6NCkZEK7hwWDHZUjit/2/U0r6XvkDl0SYnoM51Hq7FhCGdLDT6zxCCOY1hexsQ==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "eslint-visitor-keys": "^3.4.3"
+ },
+ "engines": {
+ "node": "^12.22.0 || ^14.17.0 || >=16.0.0"
+ },
+ "funding": {
+ "url": "https://opencollective.com/eslint"
+ },
+ "peerDependencies": {
+ "eslint": "^6.0.0 || ^7.0.0 || >=8.0.0"
+ }
+ },
+ "node_modules/@eslint-community/eslint-utils/node_modules/eslint-visitor-keys": {
+ "version": "3.4.3",
+ "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.4.3.tgz",
+ "integrity": "sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==",
+ "dev": true,
+ "license": "Apache-2.0",
+ "engines": {
+ "node": "^12.22.0 || ^14.17.0 || >=16.0.0"
+ },
+ "funding": {
+ "url": "https://opencollective.com/eslint"
+ }
+ },
+ "node_modules/@eslint-community/regexpp": {
+ "version": "4.12.2",
+ "resolved": "https://registry.npmjs.org/@eslint-community/regexpp/-/regexpp-4.12.2.tgz",
+ "integrity": "sha512-EriSTlt5OC9/7SXkRSCAhfSxxoSUgBm33OH+IkwbdpgoqsSsUg7y3uh+IICI/Qg4BBWr3U2i39RpmycbxMq4ew==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": "^12.0.0 || ^14.0.0 || >=16.0.0"
+ }
+ },
+ "node_modules/@eslint/config-array": {
+ "version": "0.21.2",
+ "resolved": "https://registry.npmjs.org/@eslint/config-array/-/config-array-0.21.2.tgz",
+ "integrity": "sha512-nJl2KGTlrf9GjLimgIru+V/mzgSK0ABCDQRvxw5BjURL7WfH5uoWmizbH7QB6MmnMBd8cIC9uceWnezL1VZWWw==",
+ "dev": true,
+ "license": "Apache-2.0",
+ "dependencies": {
+ "@eslint/object-schema": "^2.1.7",
+ "debug": "^4.3.1",
+ "minimatch": "^3.1.5"
+ },
+ "engines": {
+ "node": "^18.18.0 || ^20.9.0 || >=21.1.0"
+ }
+ },
+ "node_modules/@eslint/config-helpers": {
+ "version": "0.4.2",
+ "resolved": "https://registry.npmjs.org/@eslint/config-helpers/-/config-helpers-0.4.2.tgz",
+ "integrity": "sha512-gBrxN88gOIf3R7ja5K9slwNayVcZgK6SOUORm2uBzTeIEfeVaIhOpCtTox3P6R7o2jLFwLFTLnC7kU/RGcYEgw==",
+ "dev": true,
+ "license": "Apache-2.0",
+ "dependencies": {
+ "@eslint/core": "^0.17.0"
+ },
+ "engines": {
+ "node": "^18.18.0 || ^20.9.0 || >=21.1.0"
+ }
+ },
+ "node_modules/@eslint/core": {
+ "version": "0.17.0",
+ "resolved": "https://registry.npmjs.org/@eslint/core/-/core-0.17.0.tgz",
+ "integrity": "sha512-yL/sLrpmtDaFEiUj1osRP4TI2MDz1AddJL+jZ7KSqvBuliN4xqYY54IfdN8qD8Toa6g1iloph1fxQNkjOxrrpQ==",
+ "dev": true,
+ "license": "Apache-2.0",
+ "dependencies": {
+ "@types/json-schema": "^7.0.15"
+ },
+ "engines": {
+ "node": "^18.18.0 || ^20.9.0 || >=21.1.0"
+ }
+ },
+ "node_modules/@eslint/eslintrc": {
+ "version": "3.3.5",
+ "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-3.3.5.tgz",
+ "integrity": "sha512-4IlJx0X0qftVsN5E+/vGujTRIFtwuLbNsVUe7TO6zYPDR1O6nFwvwhIKEKSrl6dZchmYBITazxKoUYOjdtjlRg==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "ajv": "^6.14.0",
+ "debug": "^4.3.2",
+ "espree": "^10.0.1",
+ "globals": "^14.0.0",
+ "ignore": "^5.2.0",
+ "import-fresh": "^3.2.1",
+ "js-yaml": "^4.1.1",
+ "minimatch": "^3.1.5",
+ "strip-json-comments": "^3.1.1"
+ },
+ "engines": {
+ "node": "^18.18.0 || ^20.9.0 || >=21.1.0"
+ },
+ "funding": {
+ "url": "https://opencollective.com/eslint"
+ }
+ },
+ "node_modules/@eslint/js": {
+ "version": "9.39.4",
+ "resolved": "https://registry.npmjs.org/@eslint/js/-/js-9.39.4.tgz",
+ "integrity": "sha512-nE7DEIchvtiFTwBw4Lfbu59PG+kCofhjsKaCWzxTpt4lfRjRMqG6uMBzKXuEcyXhOHoUp9riAm7/aWYGhXZ9cw==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": "^18.18.0 || ^20.9.0 || >=21.1.0"
+ },
+ "funding": {
+ "url": "https://eslint.org/donate"
+ }
+ },
+ "node_modules/@eslint/object-schema": {
+ "version": "2.1.7",
+ "resolved": "https://registry.npmjs.org/@eslint/object-schema/-/object-schema-2.1.7.tgz",
+ "integrity": "sha512-VtAOaymWVfZcmZbp6E2mympDIHvyjXs/12LqWYjVw6qjrfF+VK+fyG33kChz3nnK+SU5/NeHOqrTEHS8sXO3OA==",
+ "dev": true,
+ "license": "Apache-2.0",
+ "engines": {
+ "node": "^18.18.0 || ^20.9.0 || >=21.1.0"
+ }
+ },
+ "node_modules/@eslint/plugin-kit": {
+ "version": "0.4.1",
+ "resolved": "https://registry.npmjs.org/@eslint/plugin-kit/-/plugin-kit-0.4.1.tgz",
+ "integrity": "sha512-43/qtrDUokr7LJqoF2c3+RInu/t4zfrpYdoSDfYyhg52rwLV6TnOvdG4fXm7IkSB3wErkcmJS9iEhjVtOSEjjA==",
+ "dev": true,
+ "license": "Apache-2.0",
+ "dependencies": {
+ "@eslint/core": "^0.17.0",
+ "levn": "^0.4.1"
+ },
+ "engines": {
+ "node": "^18.18.0 || ^20.9.0 || >=21.1.0"
+ }
+ },
+ "node_modules/@humanfs/core": {
+ "version": "0.19.2",
+ "resolved": "https://registry.npmjs.org/@humanfs/core/-/core-0.19.2.tgz",
+ "integrity": "sha512-UhXNm+CFMWcbChXywFwkmhqjs3PRCmcSa/hfBgLIb7oQ5HNb1wS0icWsGtSAUNgefHeI+eBrA8I1fxmbHsGdvA==",
+ "dev": true,
+ "license": "Apache-2.0",
+ "dependencies": {
+ "@humanfs/types": "^0.15.0"
+ },
+ "engines": {
+ "node": ">=18.18.0"
+ }
+ },
+ "node_modules/@humanfs/node": {
+ "version": "0.16.8",
+ "resolved": "https://registry.npmjs.org/@humanfs/node/-/node-0.16.8.tgz",
+ "integrity": "sha512-gE1eQNZ3R++kTzFUpdGlpmy8kDZD/MLyHqDwqjkVQI0JMdI1D51sy1H958PNXYkM2rAac7e5/CnIKZrHtPh3BQ==",
+ "dev": true,
+ "license": "Apache-2.0",
+ "dependencies": {
+ "@humanfs/core": "^0.19.2",
+ "@humanfs/types": "^0.15.0",
+ "@humanwhocodes/retry": "^0.4.0"
+ },
+ "engines": {
+ "node": ">=18.18.0"
+ }
+ },
+ "node_modules/@humanfs/types": {
+ "version": "0.15.0",
+ "resolved": "https://registry.npmjs.org/@humanfs/types/-/types-0.15.0.tgz",
+ "integrity": "sha512-ZZ1w0aoQkwuUuC7Yf+7sdeaNfqQiiLcSRbfI08oAxqLtpXQr9AIVX7Ay7HLDuiLYAaFPu8oBYNq/QIi9URHJ3Q==",
+ "dev": true,
+ "license": "Apache-2.0",
+ "engines": {
+ "node": ">=18.18.0"
+ }
+ },
+ "node_modules/@humanwhocodes/module-importer": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/@humanwhocodes/module-importer/-/module-importer-1.0.1.tgz",
+ "integrity": "sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA==",
+ "dev": true,
+ "license": "Apache-2.0",
+ "engines": {
+ "node": ">=12.22"
+ },
+ "funding": {
+ "type": "github",
+ "url": "https://github.com/sponsors/nzakas"
+ }
+ },
+ "node_modules/@humanwhocodes/retry": {
+ "version": "0.4.3",
+ "resolved": "https://registry.npmjs.org/@humanwhocodes/retry/-/retry-0.4.3.tgz",
+ "integrity": "sha512-bV0Tgo9K4hfPCek+aMAn81RppFKv2ySDQeMoSZuvTASywNTnVJCArCZE2FWqpvIatKu7VMRLWlR1EazvVhDyhQ==",
+ "dev": true,
+ "license": "Apache-2.0",
+ "engines": {
+ "node": ">=18.18"
+ },
+ "funding": {
+ "type": "github",
+ "url": "https://github.com/sponsors/nzakas"
+ }
+ },
+ "node_modules/@img/colour": {
+ "version": "1.1.0",
+ "resolved": "https://registry.npmjs.org/@img/colour/-/colour-1.1.0.tgz",
+ "integrity": "sha512-Td76q7j57o/tLVdgS746cYARfSyxk8iEfRxewL9h4OMzYhbW4TAcppl0mT4eyqXddh6L/jwoM75mo7ixa/pCeQ==",
+ "devOptional": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/@img/sharp-darwin-arm64": {
+ "version": "0.35.3",
+ "resolved": "https://registry.npmjs.org/@img/sharp-darwin-arm64/-/sharp-darwin-arm64-0.35.3.tgz",
+ "integrity": "sha512-RMnFX7YQsMoh7lWfcM4NEHHymBX/rLuKNPVM84XE9ONPcaSCDgE7CHIHpSgPcO2xcRthgBy1HfNO319mwhIAkg==",
+ "cpu": [
+ "arm64"
+ ],
+ "dev": true,
+ "license": "Apache-2.0",
+ "optional": true,
+ "os": [
+ "darwin"
+ ],
+ "engines": {
+ "node": ">=20.9.0"
+ },
+ "funding": {
+ "url": "https://opencollective.com/libvips"
+ },
+ "optionalDependencies": {
+ "@img/sharp-libvips-darwin-arm64": "1.3.2"
+ }
+ },
+ "node_modules/@img/sharp-darwin-x64": {
+ "version": "0.35.3",
+ "resolved": "https://registry.npmjs.org/@img/sharp-darwin-x64/-/sharp-darwin-x64-0.35.3.tgz",
+ "integrity": "sha512-Xo+5uFBtLN0BKqieTxiFzFPQAUlBbbH5iBKyRX/z1JrbnYsHTfKJnUfL8+p2TPXr1pXqao4eeL4Rl144uDpK9w==",
+ "cpu": [
+ "x64"
+ ],
+ "dev": true,
+ "license": "Apache-2.0",
+ "optional": true,
+ "os": [
+ "darwin"
+ ],
+ "engines": {
+ "node": ">=20.9.0"
+ },
+ "funding": {
+ "url": "https://opencollective.com/libvips"
+ },
+ "optionalDependencies": {
+ "@img/sharp-libvips-darwin-x64": "1.3.2"
+ }
+ },
+ "node_modules/@img/sharp-freebsd-wasm32": {
+ "version": "0.35.3",
+ "resolved": "https://registry.npmjs.org/@img/sharp-freebsd-wasm32/-/sharp-freebsd-wasm32-0.35.3.tgz",
+ "integrity": "sha512-lUxcqWIj2wMQ9BrwNjngcr1gWUr5xgaGThBRqPPalIC2n67Cqj1uPh8NnA/ZhAg8hUbKl+kVHKwgUIwe6ZYPrg==",
+ "dev": true,
+ "license": "Apache-2.0",
+ "optional": true,
+ "os": [
+ "freebsd"
+ ],
+ "dependencies": {
+ "@img/sharp-wasm32": "0.35.3"
+ },
+ "engines": {
+ "node": ">=20.9.0"
+ },
+ "funding": {
+ "url": "https://opencollective.com/libvips"
+ }
+ },
+ "node_modules/@img/sharp-libvips-darwin-arm64": {
+ "version": "1.3.2",
+ "resolved": "https://registry.npmjs.org/@img/sharp-libvips-darwin-arm64/-/sharp-libvips-darwin-arm64-1.3.2.tgz",
+ "integrity": "sha512-9J6ypZFpQBj4YnePGoq/S38w6nz+vqg5WZLrLGY4YuSemdMq47GMLBPO42MzwdGwpg/agZ7xzZcFHa48xlywfg==",
+ "cpu": [
+ "arm64"
+ ],
+ "dev": true,
+ "license": "LGPL-3.0-or-later",
+ "optional": true,
+ "os": [
+ "darwin"
+ ],
+ "funding": {
+ "url": "https://opencollective.com/libvips"
+ }
+ },
+ "node_modules/@img/sharp-libvips-darwin-x64": {
+ "version": "1.3.2",
+ "resolved": "https://registry.npmjs.org/@img/sharp-libvips-darwin-x64/-/sharp-libvips-darwin-x64-1.3.2.tgz",
+ "integrity": "sha512-m2pW1n6cns9VaubNwsZ+c3CRYjxNQWgJ5gPlnL1nbBcpkBvFm6SCFN5o0psFHI8w9n11NKhFkeEDns98tiqbEw==",
+ "cpu": [
+ "x64"
+ ],
+ "dev": true,
+ "license": "LGPL-3.0-or-later",
+ "optional": true,
+ "os": [
+ "darwin"
+ ],
+ "funding": {
+ "url": "https://opencollective.com/libvips"
+ }
+ },
+ "node_modules/@img/sharp-libvips-linux-arm": {
+ "version": "1.3.2",
+ "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-arm/-/sharp-libvips-linux-arm-1.3.2.tgz",
+ "integrity": "sha512-1eMLzy92I4J6rmi4mAT8yC3HxOtniyGELlzGbNMLLeqe052ahFQ0h6LFq+lh5DsDIdYViIDst08abvSbcEdLXQ==",
+ "cpu": [
+ "arm"
+ ],
+ "dev": true,
+ "license": "LGPL-3.0-or-later",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "funding": {
+ "url": "https://opencollective.com/libvips"
+ }
+ },
+ "node_modules/@img/sharp-libvips-linux-arm64": {
+ "version": "1.3.2",
+ "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-arm64/-/sharp-libvips-linux-arm64-1.3.2.tgz",
+ "integrity": "sha512-dqVSFynCox4C/J8kT16V7SIFAns0IjgLwkvYT7p8LQVmJ5OS5b6tI9IGflxTeuBS//zXeFIUbwt5dwxyZ17cnA==",
+ "cpu": [
+ "arm64"
+ ],
+ "dev": true,
+ "license": "LGPL-3.0-or-later",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "funding": {
+ "url": "https://opencollective.com/libvips"
+ }
+ },
+ "node_modules/@img/sharp-libvips-linux-ppc64": {
+ "version": "1.3.2",
+ "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-ppc64/-/sharp-libvips-linux-ppc64-1.3.2.tgz",
+ "integrity": "sha512-3z0NHDxD6n5I9gc05U1eW1AyRm+Gznzq3naMrthPNqE6oYykcogW0l/jfpJdjYnuNl8R7yI9pNbE1XiUeyq0Aw==",
+ "cpu": [
+ "ppc64"
+ ],
+ "dev": true,
+ "license": "LGPL-3.0-or-later",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "funding": {
+ "url": "https://opencollective.com/libvips"
+ }
+ },
+ "node_modules/@img/sharp-libvips-linux-riscv64": {
+ "version": "1.3.2",
+ "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-riscv64/-/sharp-libvips-linux-riscv64-1.3.2.tgz",
+ "integrity": "sha512-bsb4rI+NldGOsXuej2r8OdSS8+zXDVaCWxyWrcv6kneTOlgAHtZABRzBBCwdsPiD90J4myNJuHpg6kA20ImW/w==",
+ "cpu": [
+ "riscv64"
+ ],
+ "dev": true,
+ "license": "LGPL-3.0-or-later",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "funding": {
+ "url": "https://opencollective.com/libvips"
+ }
+ },
+ "node_modules/@img/sharp-libvips-linux-s390x": {
+ "version": "1.3.2",
+ "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-s390x/-/sharp-libvips-linux-s390x-1.3.2.tgz",
+ "integrity": "sha512-/ABshyj8gCpyIrNXnHn4LorDJ0HHm1VhXPBlxZ8zAtfVPAaSafXPGn+sUSIRiwaSBy0mmFjSjiXI5mkcwdChKQ==",
+ "cpu": [
+ "s390x"
+ ],
+ "dev": true,
+ "license": "LGPL-3.0-or-later",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "funding": {
+ "url": "https://opencollective.com/libvips"
+ }
+ },
+ "node_modules/@img/sharp-libvips-linux-x64": {
+ "version": "1.3.2",
+ "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-x64/-/sharp-libvips-linux-x64-1.3.2.tgz",
+ "integrity": "sha512-ITPEtgffGJ0S6G9dRyw/366tJQqFRcHWPHhC+Stpg3Z8AEMrDrTr2lhdz4f/Y/HMbRh//7Z5mBzEpVdi62Oc3w==",
+ "cpu": [
+ "x64"
+ ],
+ "dev": true,
+ "license": "LGPL-3.0-or-later",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "funding": {
+ "url": "https://opencollective.com/libvips"
+ }
+ },
+ "node_modules/@img/sharp-libvips-linuxmusl-arm64": {
+ "version": "1.3.2",
+ "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linuxmusl-arm64/-/sharp-libvips-linuxmusl-arm64-1.3.2.tgz",
+ "integrity": "sha512-zE9EdiUzUmg5mDT5a1rk5fYJ6GWPloTwWBYDS14naqHsL+EaMpDj1AWnpLgh3u0YCORv2Tt50wrcrpYqkP97Kw==",
+ "cpu": [
+ "arm64"
+ ],
+ "dev": true,
+ "license": "LGPL-3.0-or-later",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "funding": {
+ "url": "https://opencollective.com/libvips"
+ }
+ },
+ "node_modules/@img/sharp-libvips-linuxmusl-x64": {
+ "version": "1.3.2",
+ "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linuxmusl-x64/-/sharp-libvips-linuxmusl-x64-1.3.2.tgz",
+ "integrity": "sha512-m0lrLiUt+lBYnCFr8qV/65yMR4E/c7/wf78I5eKTdkEakFAlZ9QlzEM3QIhhAwVeUhLAHLcCq7a7Vszq/oFNZQ==",
+ "cpu": [
+ "x64"
+ ],
+ "dev": true,
+ "license": "LGPL-3.0-or-later",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "funding": {
+ "url": "https://opencollective.com/libvips"
+ }
+ },
+ "node_modules/@img/sharp-linux-arm": {
+ "version": "0.35.3",
+ "resolved": "https://registry.npmjs.org/@img/sharp-linux-arm/-/sharp-linux-arm-0.35.3.tgz",
+ "integrity": "sha512-affVWCTLooy8TSxbDx2qkzuDeaWLNVBA+P//FNBirHsXpP2fuBhk5AuboYUnrDnzoXes8GFjpTx0SBFOCRg+FA==",
+ "cpu": [
+ "arm"
+ ],
+ "dev": true,
+ "license": "Apache-2.0",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">=20.9.0"
+ },
+ "funding": {
+ "url": "https://opencollective.com/libvips"
+ },
+ "optionalDependencies": {
+ "@img/sharp-libvips-linux-arm": "1.3.2"
+ }
+ },
+ "node_modules/@img/sharp-linux-arm64": {
+ "version": "0.35.3",
+ "resolved": "https://registry.npmjs.org/@img/sharp-linux-arm64/-/sharp-linux-arm64-0.35.3.tgz",
+ "integrity": "sha512-QgKDspHPnrU+GQ55XPhGwyhC8acLVOOSyAvo1oVfFmrIXLkDNmGWzAfDZ4xK8oSA1qBQrALcHX0G5UZni/SuFQ==",
+ "cpu": [
+ "arm64"
+ ],
+ "dev": true,
+ "license": "Apache-2.0",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">=20.9.0"
+ },
+ "funding": {
+ "url": "https://opencollective.com/libvips"
+ },
+ "optionalDependencies": {
+ "@img/sharp-libvips-linux-arm64": "1.3.2"
+ }
+ },
+ "node_modules/@img/sharp-linux-ppc64": {
+ "version": "0.35.3",
+ "resolved": "https://registry.npmjs.org/@img/sharp-linux-ppc64/-/sharp-linux-ppc64-0.35.3.tgz",
+ "integrity": "sha512-sMd8rDxmpLOwv/7N44klFjOD5DUO7FLdjiXDI0hoxYaf7Ar262dQIEkosE98bps+5HPLtp/EvNqeqQtOycP/IA==",
+ "cpu": [
+ "ppc64"
+ ],
+ "dev": true,
+ "license": "Apache-2.0",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">=20.9.0"
+ },
+ "funding": {
+ "url": "https://opencollective.com/libvips"
+ },
+ "optionalDependencies": {
+ "@img/sharp-libvips-linux-ppc64": "1.3.2"
+ }
+ },
+ "node_modules/@img/sharp-linux-riscv64": {
+ "version": "0.35.3",
+ "resolved": "https://registry.npmjs.org/@img/sharp-linux-riscv64/-/sharp-linux-riscv64-0.35.3.tgz",
+ "integrity": "sha512-0Eob78yjlYPfL5vMNWAW55l3R9Y6BQS/gOfe0ZcP9mEz9ohhKSt4im1hayiknXgf8AWrFqMvJcKIdmLmEe7yeQ==",
+ "cpu": [
+ "riscv64"
+ ],
+ "dev": true,
+ "license": "Apache-2.0",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">=20.9.0"
+ },
+ "funding": {
+ "url": "https://opencollective.com/libvips"
+ },
+ "optionalDependencies": {
+ "@img/sharp-libvips-linux-riscv64": "1.3.2"
+ }
+ },
+ "node_modules/@img/sharp-linux-s390x": {
+ "version": "0.35.3",
+ "resolved": "https://registry.npmjs.org/@img/sharp-linux-s390x/-/sharp-linux-s390x-0.35.3.tgz",
+ "integrity": "sha512-KgAxQ0DxpNOq1rG2t5cgTgShJFGSuU7XO45cqC+1NVOuZnP6tlgZRuSYOfNupGkHID0o3cJOsw4DVeJpMovcGw==",
+ "cpu": [
+ "s390x"
+ ],
+ "dev": true,
+ "license": "Apache-2.0",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">=20.9.0"
+ },
+ "funding": {
+ "url": "https://opencollective.com/libvips"
+ },
+ "optionalDependencies": {
+ "@img/sharp-libvips-linux-s390x": "1.3.2"
+ }
+ },
+ "node_modules/@img/sharp-linux-x64": {
+ "version": "0.35.3",
+ "resolved": "https://registry.npmjs.org/@img/sharp-linux-x64/-/sharp-linux-x64-0.35.3.tgz",
+ "integrity": "sha512-8pqvxubL2PGdhlPy6GLqzDYMUjyRmKAwKHYKixpdJYBUK7PJ0C029XdsnpFIdgRZG68fZiGdHVWcKPvtiPB4cA==",
+ "cpu": [
+ "x64"
+ ],
+ "dev": true,
+ "license": "Apache-2.0",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">=20.9.0"
+ },
+ "funding": {
+ "url": "https://opencollective.com/libvips"
+ },
+ "optionalDependencies": {
+ "@img/sharp-libvips-linux-x64": "1.3.2"
+ }
+ },
+ "node_modules/@img/sharp-linuxmusl-arm64": {
+ "version": "0.35.3",
+ "resolved": "https://registry.npmjs.org/@img/sharp-linuxmusl-arm64/-/sharp-linuxmusl-arm64-0.35.3.tgz",
+ "integrity": "sha512-Vz0iQjzzcSX3HCbfwFfCSG/9SCIqyO0mH2sXyiHaAYfBk0cRsCWXRyQYX0ovCK/PAQBbTzQ0dsPQHh5MAFL59w==",
+ "cpu": [
+ "arm64"
+ ],
+ "dev": true,
+ "license": "Apache-2.0",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">=20.9.0"
+ },
+ "funding": {
+ "url": "https://opencollective.com/libvips"
+ },
+ "optionalDependencies": {
+ "@img/sharp-libvips-linuxmusl-arm64": "1.3.2"
+ }
+ },
+ "node_modules/@img/sharp-linuxmusl-x64": {
+ "version": "0.35.3",
+ "resolved": "https://registry.npmjs.org/@img/sharp-linuxmusl-x64/-/sharp-linuxmusl-x64-0.35.3.tgz",
+ "integrity": "sha512-6O1NPKcDVj9QEdg7Hx549EX8U0rp6yXQERqru6yRN7fGBn32UvIRJUlWnk+8xDCiG76hXVBbX82NZ/ZKr0euIg==",
+ "cpu": [
+ "x64"
+ ],
+ "dev": true,
+ "license": "Apache-2.0",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">=20.9.0"
+ },
+ "funding": {
+ "url": "https://opencollective.com/libvips"
+ },
+ "optionalDependencies": {
+ "@img/sharp-libvips-linuxmusl-x64": "1.3.2"
+ }
+ },
+ "node_modules/@img/sharp-wasm32": {
+ "version": "0.35.3",
+ "resolved": "https://registry.npmjs.org/@img/sharp-wasm32/-/sharp-wasm32-0.35.3.tgz",
+ "integrity": "sha512-cZ0XkcYGpHZkqW6iCkqTcmUC0CD9DhD5d/qeZlZkfRBn6GnHniZXLUo5+9xw8Iv76YE6LQFN9YNBlKREcCG76w==",
+ "dev": true,
+ "license": "Apache-2.0 AND LGPL-3.0-or-later AND MIT",
+ "optional": true,
+ "dependencies": {
+ "@emnapi/runtime": "^1.11.1"
+ },
+ "engines": {
+ "node": ">=20.9.0"
+ },
+ "funding": {
+ "url": "https://opencollective.com/libvips"
+ }
+ },
+ "node_modules/@img/sharp-webcontainers-wasm32": {
+ "version": "0.35.3",
+ "resolved": "https://registry.npmjs.org/@img/sharp-webcontainers-wasm32/-/sharp-webcontainers-wasm32-0.35.3.tgz",
+ "integrity": "sha512-2rnq7bX3NzeR2T4YWgz8qiG4h3TSdMe+vN1iQXpJleSJ3SM5zQ8Fy2SyyXAWlbxpEZ2Y+Z4u1BePgJEYbSy80Q==",
+ "cpu": [
+ "wasm32"
+ ],
+ "dev": true,
+ "license": "Apache-2.0",
+ "optional": true,
+ "dependencies": {
+ "@img/sharp-wasm32": "0.35.3"
+ },
+ "engines": {
+ "node": ">=20.9.0"
+ },
+ "funding": {
+ "url": "https://opencollective.com/libvips"
+ }
+ },
+ "node_modules/@img/sharp-win32-arm64": {
+ "version": "0.35.3",
+ "resolved": "https://registry.npmjs.org/@img/sharp-win32-arm64/-/sharp-win32-arm64-0.35.3.tgz",
+ "integrity": "sha512-4bPwFdMbeC4JQ8L8LOyWp6nsHcboP5fxkp6iPOXz2Vg49R42TuMs2whkJ5OAP4/Ul035qOzy0AecOF9VOscn4w==",
+ "cpu": [
+ "arm64"
+ ],
+ "dev": true,
+ "license": "Apache-2.0 AND LGPL-3.0-or-later",
+ "optional": true,
+ "os": [
+ "win32"
+ ],
+ "engines": {
+ "node": ">=20.9.0"
+ },
+ "funding": {
+ "url": "https://opencollective.com/libvips"
+ }
+ },
+ "node_modules/@img/sharp-win32-ia32": {
+ "version": "0.35.3",
+ "resolved": "https://registry.npmjs.org/@img/sharp-win32-ia32/-/sharp-win32-ia32-0.35.3.tgz",
+ "integrity": "sha512-r53mXsBN6lFUDiST764SvgwUdHAqM4rPAiDzAmf4fLoB6X/rkfyTrLCg6+g17wJJiCmB3JYgHuUldCWUIRFSXw==",
+ "cpu": [
+ "ia32"
+ ],
+ "dev": true,
+ "license": "Apache-2.0 AND LGPL-3.0-or-later",
+ "optional": true,
+ "os": [
+ "win32"
+ ],
+ "engines": {
+ "node": "^20.9.0"
+ },
+ "funding": {
+ "url": "https://opencollective.com/libvips"
+ }
+ },
+ "node_modules/@img/sharp-win32-x64": {
+ "version": "0.35.3",
+ "resolved": "https://registry.npmjs.org/@img/sharp-win32-x64/-/sharp-win32-x64-0.35.3.tgz",
+ "integrity": "sha512-D4y1vNeZrIIJCN+uHaWVtH86B+aCrdMYYjicy9pXHvbGZeGYLLSd3wdVuC37FxVXlU1ARsk84eKWfWMXGYEqvA==",
+ "cpu": [
+ "x64"
+ ],
+ "dev": true,
+ "license": "Apache-2.0 AND LGPL-3.0-or-later",
+ "optional": true,
+ "os": [
+ "win32"
+ ],
+ "engines": {
+ "node": ">=20.9.0"
+ },
+ "funding": {
+ "url": "https://opencollective.com/libvips"
+ }
+ },
+ "node_modules/@jridgewell/gen-mapping": {
+ "version": "0.3.13",
+ "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.13.tgz",
+ "integrity": "sha512-2kkt/7niJ6MgEPxF0bYdQ6etZaA+fQvDcLKckhy1yIQOzaoKjBBjSj63/aLVjYE3qhRt5dvM+uUyfCg6UKCBbA==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@jridgewell/sourcemap-codec": "^1.5.0",
+ "@jridgewell/trace-mapping": "^0.3.24"
+ }
+ },
+ "node_modules/@jridgewell/remapping": {
+ "version": "2.3.5",
+ "resolved": "https://registry.npmjs.org/@jridgewell/remapping/-/remapping-2.3.5.tgz",
+ "integrity": "sha512-LI9u/+laYG4Ds1TDKSJW2YPrIlcVYOwi2fUC6xB43lueCjgxV4lffOCZCtYFiH6TNOX+tQKXx97T4IKHbhyHEQ==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@jridgewell/gen-mapping": "^0.3.5",
+ "@jridgewell/trace-mapping": "^0.3.24"
+ }
+ },
+ "node_modules/@jridgewell/resolve-uri": {
+ "version": "3.1.2",
+ "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz",
+ "integrity": "sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=6.0.0"
+ }
+ },
+ "node_modules/@jridgewell/source-map": {
+ "version": "0.3.11",
+ "resolved": "https://registry.npmjs.org/@jridgewell/source-map/-/source-map-0.3.11.tgz",
+ "integrity": "sha512-ZMp1V8ZFcPG5dIWnQLr3NSI1MiCU7UETdS/A0G8V/XWHvJv3ZsFqutJn1Y5RPmAPX6F3BiE397OqveU/9NCuIA==",
+ "dev": true,
+ "license": "MIT",
+ "peer": true,
+ "dependencies": {
+ "@jridgewell/gen-mapping": "^0.3.5",
+ "@jridgewell/trace-mapping": "^0.3.25"
+ }
+ },
+ "node_modules/@jridgewell/sourcemap-codec": {
+ "version": "1.5.5",
+ "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.5.tgz",
+ "integrity": "sha512-cYQ9310grqxueWbl+WuIUIaiUaDcj7WOq5fVhEljNVgRfOUhY9fy2zTvfoqWsnebh8Sl70VScFbICvJnLKB0Og==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/@jridgewell/trace-mapping": {
+ "version": "0.3.31",
+ "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.31.tgz",
+ "integrity": "sha512-zzNR+SdQSDJzc8joaeP8QQoCQr8NuYx2dIIytl1QeBEZHJ9uW6hebsrYgbz8hJwUQao3TWCMtmfV8Nu1twOLAw==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@jridgewell/resolve-uri": "^3.1.0",
+ "@jridgewell/sourcemap-codec": "^1.4.14"
+ }
+ },
+ "node_modules/@napi-rs/wasm-runtime": {
+ "version": "0.2.12",
+ "resolved": "https://registry.npmjs.org/@napi-rs/wasm-runtime/-/wasm-runtime-0.2.12.tgz",
+ "integrity": "sha512-ZVWUcfwY4E/yPitQJl481FjFo3K22D6qF0DuFH6Y/nbnE11GY5uguDxZMGXPQ8WQ0128MXQD7TnfHyK4oWoIJQ==",
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "dependencies": {
+ "@emnapi/core": "^1.4.3",
+ "@emnapi/runtime": "^1.4.3",
+ "@tybys/wasm-util": "^0.10.0"
+ }
+ },
+ "node_modules/@next/env": {
+ "version": "16.2.12",
+ "resolved": "https://registry.npmjs.org/@next/env/-/env-16.2.12.tgz",
+ "integrity": "sha512-d0Z5Bc13Fa4nR8pFAKx2jay2yhJM16vlfHbTzYnUQAxlNb6B6lmn4hjt69lYNt4kRtyYP6gEM49lPRHNbIyneg==",
+ "license": "MIT"
+ },
+ "node_modules/@next/eslint-plugin-next": {
+ "version": "16.2.12",
+ "resolved": "https://registry.npmjs.org/@next/eslint-plugin-next/-/eslint-plugin-next-16.2.12.tgz",
+ "integrity": "sha512-uF2z/qAK2q7B5/6CpnFcBRX6jOq5iCO+Uqh1UkJhXljX1JwLarLYhhoJadO6dPb6moTprOKewMXheBcbIoSbug==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "fast-glob": "3.3.1"
+ }
+ },
+ "node_modules/@next/swc-darwin-arm64": {
+ "version": "16.2.12",
+ "resolved": "https://registry.npmjs.org/@next/swc-darwin-arm64/-/swc-darwin-arm64-16.2.12.tgz",
+ "integrity": "sha512-0W1R0teHWJrqKX0FH20IzzIWAOuGtBxPGuObrxy1lE8hQvCFj49KE8a3WUg0D7sq6rn6zkM4c7YGUnhudBS6oA==",
+ "cpu": [
+ "arm64"
+ ],
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "darwin"
+ ],
+ "engines": {
+ "node": ">= 10"
+ }
+ },
+ "node_modules/@next/swc-darwin-x64": {
+ "version": "16.2.12",
+ "resolved": "https://registry.npmjs.org/@next/swc-darwin-x64/-/swc-darwin-x64-16.2.12.tgz",
+ "integrity": "sha512-Hy5Ls099+aFUmOLmIgPfLqNi6iCwhL3uQCssz5rWk+5Nkc6TUKCE83DY5BbNylfm3+mfwcSFnLRfrZDJhVxdtw==",
+ "cpu": [
+ "x64"
+ ],
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "darwin"
+ ],
+ "engines": {
+ "node": ">= 10"
+ }
+ },
+ "node_modules/@next/swc-linux-arm64-gnu": {
+ "version": "16.2.12",
+ "resolved": "https://registry.npmjs.org/@next/swc-linux-arm64-gnu/-/swc-linux-arm64-gnu-16.2.12.tgz",
+ "integrity": "sha512-+YqU2h1cQkHsGfvjAsrSmst8UIFBibBGm5x3Xgel8NLMiDQtNOM4sM2GOEMvG5YiOBNeN/Ykk8cQC2S0Xrqljg==",
+ "cpu": [
+ "arm64"
+ ],
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">= 10"
+ }
+ },
+ "node_modules/@next/swc-linux-arm64-musl": {
+ "version": "16.2.12",
+ "resolved": "https://registry.npmjs.org/@next/swc-linux-arm64-musl/-/swc-linux-arm64-musl-16.2.12.tgz",
+ "integrity": "sha512-0qjhiYBaKAqF63LA1ZWAAnKTzFUguAaZiRa5etMLGGPj/B6uEVjtIZldIzFEp3wHlB0koK6aTzqPtSdplTCjoA==",
+ "cpu": [
+ "arm64"
+ ],
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">= 10"
+ }
+ },
+ "node_modules/@next/swc-linux-x64-gnu": {
+ "version": "16.2.12",
+ "resolved": "https://registry.npmjs.org/@next/swc-linux-x64-gnu/-/swc-linux-x64-gnu-16.2.12.tgz",
+ "integrity": "sha512-7A3q26W+h7gnA15uqBToNuDqBEFZZcqh0mW2mn4AJh/G5pdg2RVE3n4slzLEliASZFG3NmsbEzng/x2Sh09mBg==",
+ "cpu": [
+ "x64"
+ ],
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">= 10"
+ }
+ },
+ "node_modules/@next/swc-linux-x64-musl": {
+ "version": "16.2.12",
+ "resolved": "https://registry.npmjs.org/@next/swc-linux-x64-musl/-/swc-linux-x64-musl-16.2.12.tgz",
+ "integrity": "sha512-qSjL/uppm+cbh21s72Ss8gkiOhQ4dExWHNGOWy6eZV7STj5WsKehgxT61beSsOj+YYQuTplL376lOCdMQU5T8w==",
+ "cpu": [
+ "x64"
+ ],
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">= 10"
+ }
+ },
+ "node_modules/@next/swc-win32-arm64-msvc": {
+ "version": "16.2.12",
+ "resolved": "https://registry.npmjs.org/@next/swc-win32-arm64-msvc/-/swc-win32-arm64-msvc-16.2.12.tgz",
+ "integrity": "sha512-X6hzsOUJac/e7AWSbn9gQ9nzHld1xWP5iyjHpYWvud8pufB679O1xg4JDyKr8Xd69Jvd+kM2Der6uftiZCmjYA==",
+ "cpu": [
+ "arm64"
+ ],
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "win32"
+ ],
+ "engines": {
+ "node": ">= 10"
+ }
+ },
+ "node_modules/@next/swc-win32-x64-msvc": {
+ "version": "16.2.12",
+ "resolved": "https://registry.npmjs.org/@next/swc-win32-x64-msvc/-/swc-win32-x64-msvc-16.2.12.tgz",
+ "integrity": "sha512-F6fakeHuFTLOPt0bslQJdf+xtT+WIP9DVn/m4y1w1mRnVPyh3D/cNvzlRkxM444xfm+IvvYNSOrKiA2CDJ0Uxw==",
+ "cpu": [
+ "x64"
+ ],
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "win32"
+ ],
+ "engines": {
+ "node": ">= 10"
+ }
+ },
+ "node_modules/@nodelib/fs.scandir": {
+ "version": "2.1.5",
+ "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz",
+ "integrity": "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@nodelib/fs.stat": "2.0.5",
+ "run-parallel": "^1.1.9"
+ },
+ "engines": {
+ "node": ">= 8"
+ }
+ },
+ "node_modules/@nodelib/fs.stat": {
+ "version": "2.0.5",
+ "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz",
+ "integrity": "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">= 8"
+ }
+ },
+ "node_modules/@nodelib/fs.walk": {
+ "version": "1.2.8",
+ "resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz",
+ "integrity": "sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@nodelib/fs.scandir": "2.1.5",
+ "fastq": "^1.6.0"
+ },
+ "engines": {
+ "node": ">= 8"
+ }
+ },
+ "node_modules/@nolyfill/is-core-module": {
+ "version": "1.0.39",
+ "resolved": "https://registry.npmjs.org/@nolyfill/is-core-module/-/is-core-module-1.0.39.tgz",
+ "integrity": "sha512-nn5ozdjYQpUCZlWGuxcJY/KpxkWQs4DcbMCmKojjyrYDEAGy4Ce19NN4v5MduafTwJlbKc99UA8YhSVqq9yPZA==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=12.4.0"
+ }
+ },
+ "node_modules/@oxc-project/types": {
+ "version": "0.130.0",
+ "resolved": "https://registry.npmjs.org/@oxc-project/types/-/types-0.130.0.tgz",
+ "integrity": "sha512-ibD2usx9JRu7f5pu2tMKMI4cpA4NgXJQoYRP4pQ7Pxmn1l6k/53qWtQWZayhYy3X4QZkt90Ot+mJEaeXouio6Q==",
+ "dev": true,
+ "license": "MIT",
+ "funding": {
+ "url": "https://github.com/sponsors/Boshen"
+ }
+ },
+ "node_modules/@poppinss/colors": {
+ "version": "4.1.6",
+ "resolved": "https://registry.npmjs.org/@poppinss/colors/-/colors-4.1.6.tgz",
+ "integrity": "sha512-H9xkIdFswbS8n1d6vmRd8+c10t2Qe+rZITbbDHHkQixH5+2x1FDGmi/0K+WgWiqQFKPSlIYB7jlH6Kpfn6Fleg==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "kleur": "^4.1.5"
+ }
+ },
+ "node_modules/@poppinss/dumper": {
+ "version": "0.6.5",
+ "resolved": "https://registry.npmjs.org/@poppinss/dumper/-/dumper-0.6.5.tgz",
+ "integrity": "sha512-NBdYIb90J7LfOI32dOewKI1r7wnkiH6m920puQ3qHUeZkxNkQiFnXVWoE6YtFSv6QOiPPf7ys6i+HWWecDz7sw==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@poppinss/colors": "^4.1.5",
+ "@sindresorhus/is": "^7.0.2",
+ "supports-color": "^10.0.0"
+ }
+ },
+ "node_modules/@poppinss/dumper/node_modules/supports-color": {
+ "version": "10.2.2",
+ "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-10.2.2.tgz",
+ "integrity": "sha512-SS+jx45GF1QjgEXQx4NJZV9ImqmO2NPz5FNsIHrsDjh2YsHnawpan7SNQ1o8NuhrbHZy9AZhIoCUiCeaW/C80g==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=18"
+ },
+ "funding": {
+ "url": "https://github.com/chalk/supports-color?sponsor=1"
+ }
+ },
+ "node_modules/@poppinss/exception": {
+ "version": "1.2.3",
+ "resolved": "https://registry.npmjs.org/@poppinss/exception/-/exception-1.2.3.tgz",
+ "integrity": "sha512-dCED+QRChTVatE9ibtoaxc+WkdzOSjYTKi/+uacHWIsfodVfpsueo3+DKpgU5Px8qXjgmXkSvhXvSCz3fnP9lw==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/@resvg/resvg-wasm": {
+ "version": "2.4.0",
+ "resolved": "https://registry.npmjs.org/@resvg/resvg-wasm/-/resvg-wasm-2.4.0.tgz",
+ "integrity": "sha512-C7c51Nn4yTxXFKvgh2txJFNweaVcfUPQxwEUFw4aWsCmfiBDJsTSwviIF8EcwjQ6k8bPyMWCl1vw4BdxE569Cg==",
+ "dev": true,
+ "license": "MPL-2.0",
+ "engines": {
+ "node": ">= 10"
+ }
+ },
+ "node_modules/@rolldown/binding-android-arm64": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/@rolldown/binding-android-arm64/-/binding-android-arm64-1.0.1.tgz",
+ "integrity": "sha512-fJI3I0r3C3Oj/zdBCpaCmBRZYf07xpaq4yCfDDoSFm+beWNzbIl26puW8RraUdugoJw/95zerNOn6jasAhzSmg==",
+ "cpu": [
+ "arm64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "android"
+ ],
+ "engines": {
+ "node": "^20.19.0 || >=22.12.0"
+ }
+ },
+ "node_modules/@rolldown/binding-darwin-arm64": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/@rolldown/binding-darwin-arm64/-/binding-darwin-arm64-1.0.1.tgz",
+ "integrity": "sha512-cKnAhWEsV7TPcA/5EAteDp6KcJZBQ2G+BqE7zayMMi7kMvwRsbv7WT9aOnn0WNl4SKEIf43vjS31iUPu80nzXg==",
+ "cpu": [
+ "arm64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "darwin"
+ ],
+ "engines": {
+ "node": "^20.19.0 || >=22.12.0"
+ }
+ },
+ "node_modules/@rolldown/binding-darwin-x64": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/@rolldown/binding-darwin-x64/-/binding-darwin-x64-1.0.1.tgz",
+ "integrity": "sha512-YKrVwQjIRBPo+5G/u03wGjbdy4q7pyzCe93DK9VJ7zkVmeg8LJ7GbgsiHWdR4xSoe4CAXRD7Bcjgbtr64bkXNg==",
+ "cpu": [
+ "x64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "darwin"
+ ],
+ "engines": {
+ "node": "^20.19.0 || >=22.12.0"
+ }
+ },
+ "node_modules/@rolldown/binding-freebsd-x64": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/@rolldown/binding-freebsd-x64/-/binding-freebsd-x64-1.0.1.tgz",
+ "integrity": "sha512-z/oBsREo46SsFqBwYtFe0kpJeBijAT48O/WXLI4suiCLBkr03RTtTJMCzSdDd2znlh8VJizL09XVkQgk8IZonw==",
+ "cpu": [
+ "x64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "freebsd"
+ ],
+ "engines": {
+ "node": "^20.19.0 || >=22.12.0"
+ }
+ },
+ "node_modules/@rolldown/binding-linux-arm-gnueabihf": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-arm-gnueabihf/-/binding-linux-arm-gnueabihf-1.0.1.tgz",
+ "integrity": "sha512-ik8q7GM11zxvYxFc2PeDcT6TBvhCQMaUxfph/M5l9sKuTs/Sjg3L+Byw0F7w0ZVLBZmx30P+gG0ECzzN+MFcmQ==",
+ "cpu": [
+ "arm"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": "^20.19.0 || >=22.12.0"
+ }
+ },
+ "node_modules/@rolldown/binding-linux-arm64-gnu": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-arm64-gnu/-/binding-linux-arm64-gnu-1.0.1.tgz",
+ "integrity": "sha512-QoSx2EkyrrdZ6kcyE8stqZ62t0Yra8Fs5ia9lOxJrh6TMQJK7gQKmscdTHf7pOXKREKrVwOtJcQG3qVSfc866A==",
+ "cpu": [
+ "arm64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": "^20.19.0 || >=22.12.0"
+ }
+ },
+ "node_modules/@rolldown/binding-linux-arm64-musl": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-arm64-musl/-/binding-linux-arm64-musl-1.0.1.tgz",
+ "integrity": "sha512-uwNwFpwKeNiZawfAWBgg0VIztPTV3ihhh1vV334h9ivnNLorxnQMU6Fz8wG1Zb4Qh9LC1/MkcyT3YlDXG3Rsgg==",
+ "cpu": [
+ "arm64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": "^20.19.0 || >=22.12.0"
+ }
+ },
+ "node_modules/@rolldown/binding-linux-ppc64-gnu": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-ppc64-gnu/-/binding-linux-ppc64-gnu-1.0.1.tgz",
+ "integrity": "sha512-zY1bul7OWr7DFBiJ++wofXvnr8B45ce3QsQUhKrIhXsygAh7bTkwyeM1bi1a2g5C/yC/N8TZyGDEoMfm/l9mpg==",
+ "cpu": [
+ "ppc64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": "^20.19.0 || >=22.12.0"
+ }
+ },
+ "node_modules/@rolldown/binding-linux-s390x-gnu": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-s390x-gnu/-/binding-linux-s390x-gnu-1.0.1.tgz",
+ "integrity": "sha512-0frlsT/f4Ft6I7SMESTKnF3cZsdicQn1dCMkF/jT9wDLE+gGoiQfv1nmT9e+s7s/fekvvy6tZM2jHvI2tkbJDQ==",
+ "cpu": [
+ "s390x"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": "^20.19.0 || >=22.12.0"
+ }
+ },
+ "node_modules/@rolldown/binding-linux-x64-gnu": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-x64-gnu/-/binding-linux-x64-gnu-1.0.1.tgz",
+ "integrity": "sha512-XABVmGp9Tg0WspTVvwduTc4fpqy6JnAUrSQe6OuyqD/03nI7r0O9OWUkMIwFrjKAIqolvqoA4ZrJppgwE0Gxmw==",
+ "cpu": [
+ "x64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": "^20.19.0 || >=22.12.0"
+ }
+ },
+ "node_modules/@rolldown/binding-linux-x64-musl": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-x64-musl/-/binding-linux-x64-musl-1.0.1.tgz",
+ "integrity": "sha512-bV4fzswuzVcKD90o/VM6QqKxnxlDq0g2BISDLNVmxrnhpv1DDbyPhCIjYfvzYLV+MvkKKnQt2Q6AO86SEBULUQ==",
+ "cpu": [
+ "x64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": "^20.19.0 || >=22.12.0"
+ }
+ },
+ "node_modules/@rolldown/binding-openharmony-arm64": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/@rolldown/binding-openharmony-arm64/-/binding-openharmony-arm64-1.0.1.tgz",
+ "integrity": "sha512-/Mh0Zhq3OP7fVs0kcQHZP6lZEthMGTaSf8UBQYSFEZDWGXXlEC+nJ6EqenaK2t4LBXMe3A+K/G2BVXXdtOr4PQ==",
+ "cpu": [
+ "arm64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "openharmony"
+ ],
+ "engines": {
+ "node": "^20.19.0 || >=22.12.0"
+ }
+ },
+ "node_modules/@rolldown/binding-wasm32-wasi": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/@rolldown/binding-wasm32-wasi/-/binding-wasm32-wasi-1.0.1.tgz",
+ "integrity": "sha512-+1xc9X45l8ufsBAm6Gjvx2qDRIY9lTVt0cgWNcJ+1gdhXvkbxePA60yRTwSTuXL09CMhyJmjpV7E3NoyxbqFQQ==",
+ "cpu": [
+ "wasm32"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "dependencies": {
+ "@emnapi/core": "1.10.0",
+ "@emnapi/runtime": "1.10.0",
+ "@napi-rs/wasm-runtime": "^1.1.4"
+ },
+ "engines": {
+ "node": "^20.19.0 || >=22.12.0"
+ }
+ },
+ "node_modules/@rolldown/binding-wasm32-wasi/node_modules/@emnapi/core": {
+ "version": "1.10.0",
+ "resolved": "https://registry.npmjs.org/@emnapi/core/-/core-1.10.0.tgz",
+ "integrity": "sha512-yq6OkJ4p82CAfPl0u9mQebQHKPJkY7WrIuk205cTYnYe+k2Z8YBh11FrbRG/H6ihirqcacOgl2BIO8oyMQLeXw==",
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "dependencies": {
+ "@emnapi/wasi-threads": "1.2.1",
+ "tslib": "^2.4.0"
+ }
+ },
+ "node_modules/@rolldown/binding-wasm32-wasi/node_modules/@emnapi/runtime": {
+ "version": "1.10.0",
+ "resolved": "https://registry.npmjs.org/@emnapi/runtime/-/runtime-1.10.0.tgz",
+ "integrity": "sha512-ewvYlk86xUoGI0zQRNq/mC+16R1QeDlKQy21Ki3oSYXNgLb45GV1P6A0M+/s6nyCuNDqe5VpaY84BzXGwVbwFA==",
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "dependencies": {
+ "tslib": "^2.4.0"
+ }
+ },
+ "node_modules/@rolldown/binding-wasm32-wasi/node_modules/@emnapi/wasi-threads": {
+ "version": "1.2.1",
+ "resolved": "https://registry.npmjs.org/@emnapi/wasi-threads/-/wasi-threads-1.2.1.tgz",
+ "integrity": "sha512-uTII7OYF+/Mes/MrcIOYp5yOtSMLBWSIoLPpcgwipoiKbli6k322tcoFsxoIIxPDqW01SQGAgko4EzZi2BNv2w==",
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "dependencies": {
+ "tslib": "^2.4.0"
+ }
+ },
+ "node_modules/@rolldown/binding-wasm32-wasi/node_modules/@napi-rs/wasm-runtime": {
+ "version": "1.1.4",
+ "resolved": "https://registry.npmjs.org/@napi-rs/wasm-runtime/-/wasm-runtime-1.1.4.tgz",
+ "integrity": "sha512-3NQNNgA1YSlJb/kMH1ildASP9HW7/7kYnRI2szWJaofaS1hWmbGI4H+d3+22aGzXXN9IJ+n+GiFVcGipJP18ow==",
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "dependencies": {
+ "@tybys/wasm-util": "^0.10.1"
+ },
+ "funding": {
+ "type": "github",
+ "url": "https://github.com/sponsors/Brooooooklyn"
+ },
+ "peerDependencies": {
+ "@emnapi/core": "^1.7.1",
+ "@emnapi/runtime": "^1.7.1"
+ }
+ },
+ "node_modules/@rolldown/binding-win32-arm64-msvc": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/@rolldown/binding-win32-arm64-msvc/-/binding-win32-arm64-msvc-1.0.1.tgz",
+ "integrity": "sha512-1D+UqZdfnuR+Jy1GgMJwi85bD40H21uNmOPRWQhw4oRSuolZ/B5rixZ45DK2KXOTCvmVCecauWgEhbw8bI7tOw==",
+ "cpu": [
+ "arm64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "win32"
+ ],
+ "engines": {
+ "node": "^20.19.0 || >=22.12.0"
+ }
+ },
+ "node_modules/@rolldown/binding-win32-x64-msvc": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/@rolldown/binding-win32-x64-msvc/-/binding-win32-x64-msvc-1.0.1.tgz",
+ "integrity": "sha512-INAycaWuhlOK3wk4mRHGsdgwYWmd9cChdPdE9bwWmy6rn9VqVNYNFGhOdXrofXUxwHIncSiPNb8tNm8knDVIeQ==",
+ "cpu": [
+ "x64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "win32"
+ ],
+ "engines": {
+ "node": "^20.19.0 || >=22.12.0"
+ }
+ },
+ "node_modules/@rolldown/pluginutils": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/@rolldown/pluginutils/-/pluginutils-1.0.1.tgz",
+ "integrity": "sha512-2j9bGt5Jh8hj+vPtgzPtl72j0yRxHAyumoo6TNfAjsLB04UtpSvPbPcDcBMxz7n+9CYB0c1GxQFxYRg2jimqGw==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/@rtsao/scc": {
+ "version": "1.1.0",
+ "resolved": "https://registry.npmjs.org/@rtsao/scc/-/scc-1.1.0.tgz",
+ "integrity": "sha512-zt6OdqaDoOnJ1ZYsCYGt9YmWzDXl4vQdKTyJev62gFhRGKdx7mcT54V9KIjg+d2wi9EXsPvAPKe7i7WjfVWB8g==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/@shuding/opentype.js": {
+ "version": "1.4.0-beta.0",
+ "resolved": "https://registry.npmjs.org/@shuding/opentype.js/-/opentype.js-1.4.0-beta.0.tgz",
+ "integrity": "sha512-3NgmNyH3l/Hv6EvsWJbsvpcpUba6R8IREQ83nH83cyakCw7uM1arZKNfHwv1Wz6jgqrF/j4x5ELvR6PnK9nTcA==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "fflate": "^0.7.3",
+ "string.prototype.codepointat": "^0.2.1"
+ },
+ "bin": {
+ "ot": "bin/ot"
+ },
+ "engines": {
+ "node": ">= 8.0.0"
+ }
+ },
+ "node_modules/@sindresorhus/is": {
+ "version": "7.2.0",
+ "resolved": "https://registry.npmjs.org/@sindresorhus/is/-/is-7.2.0.tgz",
+ "integrity": "sha512-P1Cz1dWaFfR4IR+U13mqqiGsLFf1KbayybWwdd2vfctdV6hDpUkgCY0nKOLLTMSoRd/jJNjtbqzf13K8DCCXQw==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=18"
+ },
+ "funding": {
+ "url": "https://github.com/sindresorhus/is?sponsor=1"
+ }
+ },
+ "node_modules/@speed-highlight/core": {
+ "version": "1.2.15",
+ "resolved": "https://registry.npmjs.org/@speed-highlight/core/-/core-1.2.15.tgz",
+ "integrity": "sha512-BMq1K3DsElxDWawkX6eLg9+CKJrTVGCBAWVuHXVUV2u0s2711qiChLSId6ikYPfxhdYocLNt3wWwSvDiTvFabw==",
+ "dev": true,
+ "license": "CC0-1.0"
+ },
+ "node_modules/@swc/helpers": {
+ "version": "0.5.15",
+ "resolved": "https://registry.npmjs.org/@swc/helpers/-/helpers-0.5.15.tgz",
+ "integrity": "sha512-JQ5TuMi45Owi4/BIMAJBoSQoOJu12oOk/gADqlcUL9JEdHB8vyjUSsxqeNXnmXHjYKMi2WcYtezGEEhqUI/E2g==",
+ "license": "Apache-2.0",
+ "dependencies": {
+ "tslib": "^2.8.0"
+ }
+ },
+ "node_modules/@tailwindcss/node": {
+ "version": "4.2.1",
+ "resolved": "https://registry.npmjs.org/@tailwindcss/node/-/node-4.2.1.tgz",
+ "integrity": "sha512-jlx6sLk4EOwO6hHe1oCGm1Q4AN/s0rSrTTPBGPM0/RQ6Uylwq17FuU8IeJJKEjtc6K6O07zsvP+gDO6MMWo7pg==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@jridgewell/remapping": "^2.3.5",
+ "enhanced-resolve": "^5.19.0",
+ "jiti": "^2.6.1",
+ "lightningcss": "1.31.1",
+ "magic-string": "^0.30.21",
+ "source-map-js": "^1.2.1",
+ "tailwindcss": "4.2.1"
+ }
+ },
+ "node_modules/@tailwindcss/oxide": {
+ "version": "4.2.1",
+ "resolved": "https://registry.npmjs.org/@tailwindcss/oxide/-/oxide-4.2.1.tgz",
+ "integrity": "sha512-yv9jeEFWnjKCI6/T3Oq50yQEOqmpmpfzG1hcZsAOaXFQPfzWprWrlHSdGPEF3WQTi8zu8ohC9Mh9J470nT5pUw==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">= 20"
+ },
+ "optionalDependencies": {
+ "@tailwindcss/oxide-android-arm64": "4.2.1",
+ "@tailwindcss/oxide-darwin-arm64": "4.2.1",
+ "@tailwindcss/oxide-darwin-x64": "4.2.1",
+ "@tailwindcss/oxide-freebsd-x64": "4.2.1",
+ "@tailwindcss/oxide-linux-arm-gnueabihf": "4.2.1",
+ "@tailwindcss/oxide-linux-arm64-gnu": "4.2.1",
+ "@tailwindcss/oxide-linux-arm64-musl": "4.2.1",
+ "@tailwindcss/oxide-linux-x64-gnu": "4.2.1",
+ "@tailwindcss/oxide-linux-x64-musl": "4.2.1",
+ "@tailwindcss/oxide-wasm32-wasi": "4.2.1",
+ "@tailwindcss/oxide-win32-arm64-msvc": "4.2.1",
+ "@tailwindcss/oxide-win32-x64-msvc": "4.2.1"
+ }
+ },
+ "node_modules/@tailwindcss/oxide-android-arm64": {
+ "version": "4.2.1",
+ "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-android-arm64/-/oxide-android-arm64-4.2.1.tgz",
+ "integrity": "sha512-eZ7G1Zm5EC8OOKaesIKuw77jw++QJ2lL9N+dDpdQiAB/c/B2wDh0QPFHbkBVrXnwNugvrbJFk1gK2SsVjwWReg==",
+ "cpu": [
+ "arm64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "android"
+ ],
+ "engines": {
+ "node": ">= 20"
+ }
+ },
+ "node_modules/@tailwindcss/oxide-darwin-arm64": {
+ "version": "4.2.1",
+ "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-darwin-arm64/-/oxide-darwin-arm64-4.2.1.tgz",
+ "integrity": "sha512-q/LHkOstoJ7pI1J0q6djesLzRvQSIfEto148ppAd+BVQK0JYjQIFSK3JgYZJa+Yzi0DDa52ZsQx2rqytBnf8Hw==",
+ "cpu": [
+ "arm64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "darwin"
+ ],
+ "engines": {
+ "node": ">= 20"
+ }
+ },
+ "node_modules/@tailwindcss/oxide-darwin-x64": {
+ "version": "4.2.1",
+ "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-darwin-x64/-/oxide-darwin-x64-4.2.1.tgz",
+ "integrity": "sha512-/f/ozlaXGY6QLbpvd/kFTro2l18f7dHKpB+ieXz+Cijl4Mt9AI2rTrpq7V+t04nK+j9XBQHnSMdeQRhbGyt6fw==",
+ "cpu": [
+ "x64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "darwin"
+ ],
+ "engines": {
+ "node": ">= 20"
+ }
+ },
+ "node_modules/@tailwindcss/oxide-freebsd-x64": {
+ "version": "4.2.1",
+ "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-freebsd-x64/-/oxide-freebsd-x64-4.2.1.tgz",
+ "integrity": "sha512-5e/AkgYJT/cpbkys/OU2Ei2jdETCLlifwm7ogMC7/hksI2fC3iiq6OcXwjibcIjPung0kRtR3TxEITkqgn0TcA==",
+ "cpu": [
+ "x64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "freebsd"
+ ],
+ "engines": {
+ "node": ">= 20"
+ }
+ },
+ "node_modules/@tailwindcss/oxide-linux-arm-gnueabihf": {
+ "version": "4.2.1",
+ "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-arm-gnueabihf/-/oxide-linux-arm-gnueabihf-4.2.1.tgz",
+ "integrity": "sha512-Uny1EcVTTmerCKt/1ZuKTkb0x8ZaiuYucg2/kImO5A5Y/kBz41/+j0gxUZl+hTF3xkWpDmHX+TaWhOtba2Fyuw==",
+ "cpu": [
+ "arm"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">= 20"
+ }
+ },
+ "node_modules/@tailwindcss/oxide-linux-arm64-gnu": {
+ "version": "4.2.1",
+ "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-arm64-gnu/-/oxide-linux-arm64-gnu-4.2.1.tgz",
+ "integrity": "sha512-CTrwomI+c7n6aSSQlsPL0roRiNMDQ/YzMD9EjcR+H4f0I1SQ8QqIuPnsVp7QgMkC1Qi8rtkekLkOFjo7OlEFRQ==",
+ "cpu": [
+ "arm64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">= 20"
+ }
+ },
+ "node_modules/@tailwindcss/oxide-linux-arm64-musl": {
+ "version": "4.2.1",
+ "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-arm64-musl/-/oxide-linux-arm64-musl-4.2.1.tgz",
+ "integrity": "sha512-WZA0CHRL/SP1TRbA5mp9htsppSEkWuQ4KsSUumYQnyl8ZdT39ntwqmz4IUHGN6p4XdSlYfJwM4rRzZLShHsGAQ==",
+ "cpu": [
+ "arm64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">= 20"
+ }
+ },
+ "node_modules/@tailwindcss/oxide-linux-x64-gnu": {
+ "version": "4.2.1",
+ "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-x64-gnu/-/oxide-linux-x64-gnu-4.2.1.tgz",
+ "integrity": "sha512-qMFzxI2YlBOLW5PhblzuSWlWfwLHaneBE0xHzLrBgNtqN6mWfs+qYbhryGSXQjFYB1Dzf5w+LN5qbUTPhW7Y5g==",
+ "cpu": [
+ "x64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">= 20"
+ }
+ },
+ "node_modules/@tailwindcss/oxide-linux-x64-musl": {
+ "version": "4.2.1",
+ "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-x64-musl/-/oxide-linux-x64-musl-4.2.1.tgz",
+ "integrity": "sha512-5r1X2FKnCMUPlXTWRYpHdPYUY6a1Ar/t7P24OuiEdEOmms5lyqjDRvVY1yy9Rmioh+AunQ0rWiOTPE8F9A3v5g==",
+ "cpu": [
+ "x64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">= 20"
+ }
+ },
+ "node_modules/@tailwindcss/oxide-wasm32-wasi": {
+ "version": "4.2.1",
+ "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-wasm32-wasi/-/oxide-wasm32-wasi-4.2.1.tgz",
+ "integrity": "sha512-MGFB5cVPvshR85MTJkEvqDUnuNoysrsRxd6vnk1Lf2tbiqNlXpHYZqkqOQalydienEWOHHFyyuTSYRsLfxFJ2Q==",
+ "bundleDependencies": [
+ "@napi-rs/wasm-runtime",
+ "@emnapi/core",
+ "@emnapi/runtime",
+ "@tybys/wasm-util",
+ "@emnapi/wasi-threads",
+ "tslib"
+ ],
+ "cpu": [
+ "wasm32"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "dependencies": {
+ "@emnapi/core": "^1.8.1",
+ "@emnapi/runtime": "^1.8.1",
+ "@emnapi/wasi-threads": "^1.1.0",
+ "@napi-rs/wasm-runtime": "^1.1.1",
+ "@tybys/wasm-util": "^0.10.1",
+ "tslib": "^2.8.1"
+ },
+ "engines": {
+ "node": ">=14.0.0"
+ }
+ },
+ "node_modules/@tailwindcss/oxide-wasm32-wasi/node_modules/@emnapi/core": {
+ "version": "1.8.1",
+ "dev": true,
+ "inBundle": true,
+ "license": "MIT",
+ "optional": true,
+ "dependencies": {
+ "@emnapi/wasi-threads": "1.1.0",
+ "tslib": "^2.4.0"
+ }
+ },
+ "node_modules/@tailwindcss/oxide-wasm32-wasi/node_modules/@emnapi/runtime": {
+ "version": "1.8.1",
+ "dev": true,
+ "inBundle": true,
+ "license": "MIT",
+ "optional": true,
+ "dependencies": {
+ "tslib": "^2.4.0"
+ }
+ },
+ "node_modules/@tailwindcss/oxide-wasm32-wasi/node_modules/@emnapi/wasi-threads": {
+ "version": "1.1.0",
+ "dev": true,
+ "inBundle": true,
+ "license": "MIT",
+ "optional": true,
+ "dependencies": {
+ "tslib": "^2.4.0"
+ }
+ },
+ "node_modules/@tailwindcss/oxide-wasm32-wasi/node_modules/@napi-rs/wasm-runtime": {
+ "version": "1.1.1",
+ "dev": true,
+ "inBundle": true,
+ "license": "MIT",
+ "optional": true,
+ "dependencies": {
+ "@emnapi/core": "^1.7.1",
+ "@emnapi/runtime": "^1.7.1",
+ "@tybys/wasm-util": "^0.10.1"
+ },
+ "funding": {
+ "type": "github",
+ "url": "https://github.com/sponsors/Brooooooklyn"
+ }
+ },
+ "node_modules/@tailwindcss/oxide-wasm32-wasi/node_modules/@tybys/wasm-util": {
+ "version": "0.10.1",
+ "dev": true,
+ "inBundle": true,
+ "license": "MIT",
+ "optional": true,
+ "dependencies": {
+ "tslib": "^2.4.0"
+ }
+ },
+ "node_modules/@tailwindcss/oxide-wasm32-wasi/node_modules/tslib": {
+ "version": "2.8.1",
+ "dev": true,
+ "inBundle": true,
+ "license": "0BSD",
+ "optional": true
+ },
+ "node_modules/@tailwindcss/oxide-win32-arm64-msvc": {
+ "version": "4.2.1",
+ "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-win32-arm64-msvc/-/oxide-win32-arm64-msvc-4.2.1.tgz",
+ "integrity": "sha512-YlUEHRHBGnCMh4Nj4GnqQyBtsshUPdiNroZj8VPkvTZSoHsilRCwXcVKnG9kyi0ZFAS/3u+qKHBdDc81SADTRA==",
+ "cpu": [
+ "arm64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "win32"
+ ],
+ "engines": {
+ "node": ">= 20"
+ }
+ },
+ "node_modules/@tailwindcss/oxide-win32-x64-msvc": {
+ "version": "4.2.1",
+ "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-win32-x64-msvc/-/oxide-win32-x64-msvc-4.2.1.tgz",
+ "integrity": "sha512-rbO34G5sMWWyrN/idLeVxAZgAKWrn5LiR3/I90Q9MkA67s6T1oB0xtTe+0heoBvHSpbU9Mk7i6uwJnpo4u21XQ==",
+ "cpu": [
+ "x64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "win32"
+ ],
+ "engines": {
+ "node": ">= 20"
+ }
+ },
+ "node_modules/@tailwindcss/postcss": {
+ "version": "4.2.1",
+ "resolved": "https://registry.npmjs.org/@tailwindcss/postcss/-/postcss-4.2.1.tgz",
+ "integrity": "sha512-OEwGIBnXnj7zJeonOh6ZG9woofIjGrd2BORfvE5p9USYKDCZoQmfqLcfNiRWoJlRWLdNPn2IgVZuWAOM4iTYMw==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@alloc/quick-lru": "^5.2.0",
+ "@tailwindcss/node": "4.2.1",
+ "@tailwindcss/oxide": "4.2.1",
+ "postcss": "^8.5.6",
+ "tailwindcss": "4.2.1"
+ }
+ },
+ "node_modules/@tybys/wasm-util": {
+ "version": "0.10.2",
+ "resolved": "https://registry.npmjs.org/@tybys/wasm-util/-/wasm-util-0.10.2.tgz",
+ "integrity": "sha512-RoBvJ2X0wuKlWFIjrwffGw1IqZHKQqzIchKaadZZfnNpsAYp2mM0h36JtPCjNDAHGgYez/15uMBpfGwchhiMgg==",
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "dependencies": {
+ "tslib": "^2.4.0"
+ }
+ },
+ "node_modules/@types/eslint": {
+ "version": "9.6.1",
+ "resolved": "https://registry.npmjs.org/@types/eslint/-/eslint-9.6.1.tgz",
+ "integrity": "sha512-FXx2pKgId/WyYo2jXw63kk7/+TY7u7AziEJxJAnSFzHlqTAS3Ync6SvgYAN/k4/PQpnnVuzoMuVnByKK2qp0ag==",
+ "dev": true,
+ "license": "MIT",
+ "peer": true,
+ "dependencies": {
+ "@types/estree": "*",
+ "@types/json-schema": "*"
+ }
+ },
+ "node_modules/@types/eslint-scope": {
+ "version": "3.7.7",
+ "resolved": "https://registry.npmjs.org/@types/eslint-scope/-/eslint-scope-3.7.7.tgz",
+ "integrity": "sha512-MzMFlSLBqNF2gcHWO0G1vP/YQyfvrxZ0bF+u7mzUdZ1/xK4A4sru+nraZz5i3iEIk1l1uyicaDVTB4QbbEkAYg==",
+ "dev": true,
+ "license": "MIT",
+ "peer": true,
+ "dependencies": {
+ "@types/eslint": "*",
+ "@types/estree": "*"
+ }
+ },
+ "node_modules/@types/estree": {
+ "version": "1.0.9",
+ "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.9.tgz",
+ "integrity": "sha512-GhdPgy1el4/ImP05X05Uw4cw2/M93BCUmnEvWZNStlCzEKME4Fkk+YpoA5OiHNQmoS7Cafb8Xa3Pya8m1Qrzeg==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/@types/json-schema": {
+ "version": "7.0.15",
+ "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.15.tgz",
+ "integrity": "sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/@types/json5": {
+ "version": "0.0.29",
+ "resolved": "https://registry.npmjs.org/@types/json5/-/json5-0.0.29.tgz",
+ "integrity": "sha512-dRLjCWHYg4oaA77cxO64oO+7JwCwnIzkZPdrrC71jQmQtlhM556pwKo5bUzqvZndkVbeFLIIi+9TC40JNF5hNQ==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/@types/node": {
+ "version": "22.19.19",
+ "resolved": "https://registry.npmjs.org/@types/node/-/node-22.19.19.tgz",
+ "integrity": "sha512-dyh/xO2Fh5bYrfWaaqGrRQQGkNdmYw6AmaAUvYeUMNTWQtvb796ikLdmTchRmOlOiIJ1TDXfWgVx1QkUlQ6Hew==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "undici-types": "~6.21.0"
+ }
+ },
+ "node_modules/@types/react": {
+ "version": "19.2.14",
+ "resolved": "https://registry.npmjs.org/@types/react/-/react-19.2.14.tgz",
+ "integrity": "sha512-ilcTH/UniCkMdtexkoCN0bI7pMcJDvmQFPvuPvmEaYA/NSfFTAgdUSLAoVjaRJm7+6PvcM+q1zYOwS4wTYMF9w==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "csstype": "^3.2.2"
+ }
+ },
+ "node_modules/@types/react-dom": {
+ "version": "19.2.3",
+ "resolved": "https://registry.npmjs.org/@types/react-dom/-/react-dom-19.2.3.tgz",
+ "integrity": "sha512-jp2L/eY6fn+KgVVQAOqYItbF0VY/YApe5Mz2F0aykSO8gx31bYCZyvSeYxCHKvzHG5eZjc+zyaS5BrBWya2+kQ==",
+ "dev": true,
+ "license": "MIT",
+ "peerDependencies": {
+ "@types/react": "^19.2.0"
+ }
+ },
+ "node_modules/@typescript-eslint/eslint-plugin": {
+ "version": "8.59.3",
+ "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-8.59.3.tgz",
+ "integrity": "sha512-PwFvSKsXGShKGW6n5bZOhGHEcCZXM8HofLK9fNsEwZXzFRjoY+XT1Vsf1zgyXdwTr0ZYz1/2tkZ0DBTT9jZjhw==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@eslint-community/regexpp": "^4.12.2",
+ "@typescript-eslint/scope-manager": "8.59.3",
+ "@typescript-eslint/type-utils": "8.59.3",
+ "@typescript-eslint/utils": "8.59.3",
+ "@typescript-eslint/visitor-keys": "8.59.3",
+ "ignore": "^7.0.5",
+ "natural-compare": "^1.4.0",
+ "ts-api-utils": "^2.5.0"
+ },
+ "engines": {
+ "node": "^18.18.0 || ^20.9.0 || >=21.1.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/typescript-eslint"
+ },
+ "peerDependencies": {
+ "@typescript-eslint/parser": "^8.59.3",
+ "eslint": "^8.57.0 || ^9.0.0 || ^10.0.0",
+ "typescript": ">=4.8.4 <6.1.0"
+ }
+ },
+ "node_modules/@typescript-eslint/eslint-plugin/node_modules/ignore": {
+ "version": "7.0.5",
+ "resolved": "https://registry.npmjs.org/ignore/-/ignore-7.0.5.tgz",
+ "integrity": "sha512-Hs59xBNfUIunMFgWAbGX5cq6893IbWg4KnrjbYwX3tx0ztorVgTDA6B2sxf8ejHJ4wz8BqGUMYlnzNBer5NvGg==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">= 4"
+ }
+ },
+ "node_modules/@typescript-eslint/parser": {
+ "version": "8.59.3",
+ "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-8.59.3.tgz",
+ "integrity": "sha512-HPwA+hVkfcriajbNvTmZv4VRauibay+cWArYUYq7u7W7PmGShMxbPxLvrwDme55a6d5alG3nrYfhyJ/G28XlLg==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@typescript-eslint/scope-manager": "8.59.3",
+ "@typescript-eslint/types": "8.59.3",
+ "@typescript-eslint/typescript-estree": "8.59.3",
+ "@typescript-eslint/visitor-keys": "8.59.3",
+ "debug": "^4.4.3"
+ },
+ "engines": {
+ "node": "^18.18.0 || ^20.9.0 || >=21.1.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/typescript-eslint"
+ },
+ "peerDependencies": {
+ "eslint": "^8.57.0 || ^9.0.0 || ^10.0.0",
+ "typescript": ">=4.8.4 <6.1.0"
+ }
+ },
+ "node_modules/@typescript-eslint/project-service": {
+ "version": "8.59.3",
+ "resolved": "https://registry.npmjs.org/@typescript-eslint/project-service/-/project-service-8.59.3.tgz",
+ "integrity": "sha512-ECiUWa/KYRGDFUqTNehaRgzDshnJfkTABJxVemHk4ko22gcr0ukloKjWvyQ64g8YCV/UI47kN1dbmjf/GaQYng==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@typescript-eslint/tsconfig-utils": "^8.59.3",
+ "@typescript-eslint/types": "^8.59.3",
+ "debug": "^4.4.3"
+ },
+ "engines": {
+ "node": "^18.18.0 || ^20.9.0 || >=21.1.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/typescript-eslint"
+ },
+ "peerDependencies": {
+ "typescript": ">=4.8.4 <6.1.0"
+ }
+ },
+ "node_modules/@typescript-eslint/scope-manager": {
+ "version": "8.59.3",
+ "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-8.59.3.tgz",
+ "integrity": "sha512-t2LvZnoEfzKtnPjgeEu41xw5gxq9mQVfYy4OoZ4Vlt0sk3JwxmhCca/AR7DwOiHrjWgjAj6as4AhRLKSDfvZIA==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@typescript-eslint/types": "8.59.3",
+ "@typescript-eslint/visitor-keys": "8.59.3"
+ },
+ "engines": {
+ "node": "^18.18.0 || ^20.9.0 || >=21.1.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/typescript-eslint"
+ }
+ },
+ "node_modules/@typescript-eslint/tsconfig-utils": {
+ "version": "8.59.3",
+ "resolved": "https://registry.npmjs.org/@typescript-eslint/tsconfig-utils/-/tsconfig-utils-8.59.3.tgz",
+ "integrity": "sha512-PcIJHjmaREXLgIAIzLnSY9VucEzz8FKXsRgFa1DmdGCK/5tJpW03TKJF01Q6VZd1lLdz2sIKPWaDUZN9dp//dw==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": "^18.18.0 || ^20.9.0 || >=21.1.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/typescript-eslint"
+ },
+ "peerDependencies": {
+ "typescript": ">=4.8.4 <6.1.0"
+ }
+ },
+ "node_modules/@typescript-eslint/type-utils": {
+ "version": "8.59.3",
+ "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-8.59.3.tgz",
+ "integrity": "sha512-g71d8QD8UaiHGvrJwyIS1hCX5r63w6Jll+4VEYhEAHXTDIqX1JgxhTAbEHtKntL9kuc4jRo7/GWw5xfCepSccQ==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@typescript-eslint/types": "8.59.3",
+ "@typescript-eslint/typescript-estree": "8.59.3",
+ "@typescript-eslint/utils": "8.59.3",
+ "debug": "^4.4.3",
+ "ts-api-utils": "^2.5.0"
+ },
+ "engines": {
+ "node": "^18.18.0 || ^20.9.0 || >=21.1.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/typescript-eslint"
+ },
+ "peerDependencies": {
+ "eslint": "^8.57.0 || ^9.0.0 || ^10.0.0",
+ "typescript": ">=4.8.4 <6.1.0"
+ }
+ },
+ "node_modules/@typescript-eslint/types": {
+ "version": "8.59.3",
+ "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-8.59.3.tgz",
+ "integrity": "sha512-ePFoH0g4ludssdRFqqDxQePCxU4WQyRa9+XVwjm7yLn0FKhMeoetC+qBEEI1Eyb1pGSDveTIT09Bvw2WhlGayg==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": "^18.18.0 || ^20.9.0 || >=21.1.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/typescript-eslint"
+ }
+ },
+ "node_modules/@typescript-eslint/typescript-estree": {
+ "version": "8.59.3",
+ "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-8.59.3.tgz",
+ "integrity": "sha512-CbRjVRAf7Lr9Kr8RopKcbY45p2VfmmHrm0ygOCYFi7oU8q19m0Fs/6iHS7kNOmwpp+ob07ZVcAqlxUod9lYdmg==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@typescript-eslint/project-service": "8.59.3",
+ "@typescript-eslint/tsconfig-utils": "8.59.3",
+ "@typescript-eslint/types": "8.59.3",
+ "@typescript-eslint/visitor-keys": "8.59.3",
+ "debug": "^4.4.3",
+ "minimatch": "^10.2.2",
+ "semver": "^7.7.3",
+ "tinyglobby": "^0.2.15",
+ "ts-api-utils": "^2.5.0"
+ },
+ "engines": {
+ "node": "^18.18.0 || ^20.9.0 || >=21.1.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/typescript-eslint"
+ },
+ "peerDependencies": {
+ "typescript": ">=4.8.4 <6.1.0"
+ }
+ },
+ "node_modules/@typescript-eslint/typescript-estree/node_modules/balanced-match": {
+ "version": "4.0.4",
+ "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-4.0.4.tgz",
+ "integrity": "sha512-BLrgEcRTwX2o6gGxGOCNyMvGSp35YofuYzw9h1IMTRmKqttAZZVU67bdb9Pr2vUHA8+j3i2tJfjO6C6+4myGTA==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": "18 || 20 || >=22"
+ }
+ },
+ "node_modules/@typescript-eslint/typescript-estree/node_modules/brace-expansion": {
+ "version": "5.0.6",
+ "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-5.0.6.tgz",
+ "integrity": "sha512-kLpxurY4Z4r9sgMsyG0Z9uzsBlgiU/EFKhj/h91/8yHu0edo7XuixOIH3VcJ8kkxs6/jPzoI6U9Vj3WqbMQ94g==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "balanced-match": "^4.0.2"
+ },
+ "engines": {
+ "node": "18 || 20 || >=22"
+ }
+ },
+ "node_modules/@typescript-eslint/typescript-estree/node_modules/minimatch": {
+ "version": "10.2.5",
+ "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-10.2.5.tgz",
+ "integrity": "sha512-MULkVLfKGYDFYejP07QOurDLLQpcjk7Fw+7jXS2R2czRQzR56yHRveU5NDJEOviH+hETZKSkIk5c+T23GjFUMg==",
+ "dev": true,
+ "license": "BlueOak-1.0.0",
+ "dependencies": {
+ "brace-expansion": "^5.0.5"
+ },
+ "engines": {
+ "node": "18 || 20 || >=22"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/isaacs"
+ }
+ },
+ "node_modules/@typescript-eslint/typescript-estree/node_modules/semver": {
+ "version": "7.8.0",
+ "resolved": "https://registry.npmjs.org/semver/-/semver-7.8.0.tgz",
+ "integrity": "sha512-AcM7dV/5ul4EekoQ29Agm5vri8JNqRyj39o0qpX6vDF2GZrtutZl5RwgD1XnZjiTAfncsJhMI48QQH3sN87YNA==",
+ "dev": true,
+ "license": "ISC",
+ "bin": {
+ "semver": "bin/semver.js"
+ },
+ "engines": {
+ "node": ">=10"
+ }
+ },
+ "node_modules/@typescript-eslint/utils": {
+ "version": "8.59.3",
+ "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-8.59.3.tgz",
+ "integrity": "sha512-JAvT14goBzRzzzZyqq3P9BLArIxTtQURUtFgQ/V7FO+eU+Gg6ES+5ymOPP1wRxXcxAYeivCk4uS3jCKWI1K8Zg==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@eslint-community/eslint-utils": "^4.9.1",
+ "@typescript-eslint/scope-manager": "8.59.3",
+ "@typescript-eslint/types": "8.59.3",
+ "@typescript-eslint/typescript-estree": "8.59.3"
+ },
+ "engines": {
+ "node": "^18.18.0 || ^20.9.0 || >=21.1.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/typescript-eslint"
+ },
+ "peerDependencies": {
+ "eslint": "^8.57.0 || ^9.0.0 || ^10.0.0",
+ "typescript": ">=4.8.4 <6.1.0"
+ }
+ },
+ "node_modules/@typescript-eslint/visitor-keys": {
+ "version": "8.59.3",
+ "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-8.59.3.tgz",
+ "integrity": "sha512-f1UQF7ggd42YiwI5wGrRaPsa+P0CINBlrkLPmGfpq/u/I/oVtecoEIfFR9ag/oa1sLOsRNZ6xehf6qMZhQGBDg==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@typescript-eslint/types": "8.59.3",
+ "eslint-visitor-keys": "^5.0.0"
+ },
+ "engines": {
+ "node": "^18.18.0 || ^20.9.0 || >=21.1.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/typescript-eslint"
+ }
+ },
+ "node_modules/@typescript-eslint/visitor-keys/node_modules/eslint-visitor-keys": {
+ "version": "5.0.1",
+ "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-5.0.1.tgz",
+ "integrity": "sha512-tD40eHxA35h0PEIZNeIjkHoDR4YjjJp34biM0mDvplBe//mB+IHCqHDGV7pxF+7MklTvighcCPPZC7ynWyjdTA==",
+ "dev": true,
+ "license": "Apache-2.0",
+ "engines": {
+ "node": "^20.19.0 || ^22.13.0 || >=24"
+ },
+ "funding": {
+ "url": "https://opencollective.com/eslint"
+ }
+ },
+ "node_modules/@unpic/core": {
+ "version": "1.0.3",
+ "resolved": "https://registry.npmjs.org/@unpic/core/-/core-1.0.3.tgz",
+ "integrity": "sha512-aum9YNVUGso7MjGLD0Rp/08kywCGLqZ03/q6VQBFFakDBOXWEc8D4kPGcZ8v5wEnGRex3lE+++bOuucBp3KJ/w==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "unpic": "^4.2.2"
+ }
+ },
+ "node_modules/@unpic/react": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/@unpic/react/-/react-1.0.2.tgz",
+ "integrity": "sha512-5RmRfELwTF8w+4zjtQGqjpvX+RU2VLvis3xDCS1O2uWk0PZN2cvatL+3/KAR3mshAuRrkFGTX1XwyAezSXaoCA==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@unpic/core": "^1.0.3"
+ },
+ "peerDependencies": {
+ "next": "^13.0.0 || ^14.0.0 || ^15.0.0 || ^16.0.0",
+ "react": "^17.0.0 || ^18.0.0 || ^19.0.0",
+ "react-dom": "^17.0.0 || ^18.0.0 || ^19.0.0"
+ },
+ "peerDependenciesMeta": {
+ "next": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/@unrs/resolver-binding-android-arm-eabi": {
+ "version": "1.11.1",
+ "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-android-arm-eabi/-/resolver-binding-android-arm-eabi-1.11.1.tgz",
+ "integrity": "sha512-ppLRUgHVaGRWUx0R0Ut06Mjo9gBaBkg3v/8AxusGLhsIotbBLuRk51rAzqLC8gq6NyyAojEXglNjzf6R948DNw==",
+ "cpu": [
+ "arm"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "android"
+ ]
+ },
+ "node_modules/@unrs/resolver-binding-android-arm64": {
+ "version": "1.11.1",
+ "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-android-arm64/-/resolver-binding-android-arm64-1.11.1.tgz",
+ "integrity": "sha512-lCxkVtb4wp1v+EoN+HjIG9cIIzPkX5OtM03pQYkG+U5O/wL53LC4QbIeazgiKqluGeVEeBlZahHalCaBvU1a2g==",
+ "cpu": [
+ "arm64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "android"
+ ]
+ },
+ "node_modules/@unrs/resolver-binding-darwin-arm64": {
+ "version": "1.11.1",
+ "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-darwin-arm64/-/resolver-binding-darwin-arm64-1.11.1.tgz",
+ "integrity": "sha512-gPVA1UjRu1Y/IsB/dQEsp2V1pm44Of6+LWvbLc9SDk1c2KhhDRDBUkQCYVWe6f26uJb3fOK8saWMgtX8IrMk3g==",
+ "cpu": [
+ "arm64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "darwin"
+ ]
+ },
+ "node_modules/@unrs/resolver-binding-darwin-x64": {
+ "version": "1.11.1",
+ "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-darwin-x64/-/resolver-binding-darwin-x64-1.11.1.tgz",
+ "integrity": "sha512-cFzP7rWKd3lZaCsDze07QX1SC24lO8mPty9vdP+YVa3MGdVgPmFc59317b2ioXtgCMKGiCLxJ4HQs62oz6GfRQ==",
+ "cpu": [
+ "x64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "darwin"
+ ]
+ },
+ "node_modules/@unrs/resolver-binding-freebsd-x64": {
+ "version": "1.11.1",
+ "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-freebsd-x64/-/resolver-binding-freebsd-x64-1.11.1.tgz",
+ "integrity": "sha512-fqtGgak3zX4DCB6PFpsH5+Kmt/8CIi4Bry4rb1ho6Av2QHTREM+47y282Uqiu3ZRF5IQioJQ5qWRV6jduA+iGw==",
+ "cpu": [
+ "x64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "freebsd"
+ ]
+ },
+ "node_modules/@unrs/resolver-binding-linux-arm-gnueabihf": {
+ "version": "1.11.1",
+ "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-linux-arm-gnueabihf/-/resolver-binding-linux-arm-gnueabihf-1.11.1.tgz",
+ "integrity": "sha512-u92mvlcYtp9MRKmP+ZvMmtPN34+/3lMHlyMj7wXJDeXxuM0Vgzz0+PPJNsro1m3IZPYChIkn944wW8TYgGKFHw==",
+ "cpu": [
+ "arm"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ]
+ },
+ "node_modules/@unrs/resolver-binding-linux-arm-musleabihf": {
+ "version": "1.11.1",
+ "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-linux-arm-musleabihf/-/resolver-binding-linux-arm-musleabihf-1.11.1.tgz",
+ "integrity": "sha512-cINaoY2z7LVCrfHkIcmvj7osTOtm6VVT16b5oQdS4beibX2SYBwgYLmqhBjA1t51CarSaBuX5YNsWLjsqfW5Cw==",
+ "cpu": [
+ "arm"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ]
+ },
+ "node_modules/@unrs/resolver-binding-linux-arm64-gnu": {
+ "version": "1.11.1",
+ "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-linux-arm64-gnu/-/resolver-binding-linux-arm64-gnu-1.11.1.tgz",
+ "integrity": "sha512-34gw7PjDGB9JgePJEmhEqBhWvCiiWCuXsL9hYphDF7crW7UgI05gyBAi6MF58uGcMOiOqSJ2ybEeCvHcq0BCmQ==",
+ "cpu": [
+ "arm64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ]
+ },
+ "node_modules/@unrs/resolver-binding-linux-arm64-musl": {
+ "version": "1.11.1",
+ "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-linux-arm64-musl/-/resolver-binding-linux-arm64-musl-1.11.1.tgz",
+ "integrity": "sha512-RyMIx6Uf53hhOtJDIamSbTskA99sPHS96wxVE/bJtePJJtpdKGXO1wY90oRdXuYOGOTuqjT8ACccMc4K6QmT3w==",
+ "cpu": [
+ "arm64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ]
+ },
+ "node_modules/@unrs/resolver-binding-linux-ppc64-gnu": {
+ "version": "1.11.1",
+ "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-linux-ppc64-gnu/-/resolver-binding-linux-ppc64-gnu-1.11.1.tgz",
+ "integrity": "sha512-D8Vae74A4/a+mZH0FbOkFJL9DSK2R6TFPC9M+jCWYia/q2einCubX10pecpDiTmkJVUH+y8K3BZClycD8nCShA==",
+ "cpu": [
+ "ppc64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ]
+ },
+ "node_modules/@unrs/resolver-binding-linux-riscv64-gnu": {
+ "version": "1.11.1",
+ "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-linux-riscv64-gnu/-/resolver-binding-linux-riscv64-gnu-1.11.1.tgz",
+ "integrity": "sha512-frxL4OrzOWVVsOc96+V3aqTIQl1O2TjgExV4EKgRY09AJ9leZpEg8Ak9phadbuX0BA4k8U5qtvMSQQGGmaJqcQ==",
+ "cpu": [
+ "riscv64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ]
+ },
+ "node_modules/@unrs/resolver-binding-linux-riscv64-musl": {
+ "version": "1.11.1",
+ "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-linux-riscv64-musl/-/resolver-binding-linux-riscv64-musl-1.11.1.tgz",
+ "integrity": "sha512-mJ5vuDaIZ+l/acv01sHoXfpnyrNKOk/3aDoEdLO/Xtn9HuZlDD6jKxHlkN8ZhWyLJsRBxfv9GYM2utQ1SChKew==",
+ "cpu": [
+ "riscv64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ]
+ },
+ "node_modules/@unrs/resolver-binding-linux-s390x-gnu": {
+ "version": "1.11.1",
+ "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-linux-s390x-gnu/-/resolver-binding-linux-s390x-gnu-1.11.1.tgz",
+ "integrity": "sha512-kELo8ebBVtb9sA7rMe1Cph4QHreByhaZ2QEADd9NzIQsYNQpt9UkM9iqr2lhGr5afh885d/cB5QeTXSbZHTYPg==",
+ "cpu": [
+ "s390x"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ]
+ },
+ "node_modules/@unrs/resolver-binding-linux-x64-gnu": {
+ "version": "1.11.1",
+ "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-linux-x64-gnu/-/resolver-binding-linux-x64-gnu-1.11.1.tgz",
+ "integrity": "sha512-C3ZAHugKgovV5YvAMsxhq0gtXuwESUKc5MhEtjBpLoHPLYM+iuwSj3lflFwK3DPm68660rZ7G8BMcwSro7hD5w==",
+ "cpu": [
+ "x64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ]
+ },
+ "node_modules/@unrs/resolver-binding-linux-x64-musl": {
+ "version": "1.11.1",
+ "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-linux-x64-musl/-/resolver-binding-linux-x64-musl-1.11.1.tgz",
+ "integrity": "sha512-rV0YSoyhK2nZ4vEswT/QwqzqQXw5I6CjoaYMOX0TqBlWhojUf8P94mvI7nuJTeaCkkds3QE4+zS8Ko+GdXuZtA==",
+ "cpu": [
+ "x64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ]
+ },
+ "node_modules/@unrs/resolver-binding-wasm32-wasi": {
+ "version": "1.11.1",
+ "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-wasm32-wasi/-/resolver-binding-wasm32-wasi-1.11.1.tgz",
+ "integrity": "sha512-5u4RkfxJm+Ng7IWgkzi3qrFOvLvQYnPBmjmZQ8+szTK/b31fQCnleNl1GgEt7nIsZRIf5PLhPwT0WM+q45x/UQ==",
+ "cpu": [
+ "wasm32"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "dependencies": {
+ "@napi-rs/wasm-runtime": "^0.2.11"
+ },
+ "engines": {
+ "node": ">=14.0.0"
+ }
+ },
+ "node_modules/@unrs/resolver-binding-win32-arm64-msvc": {
+ "version": "1.11.1",
+ "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-win32-arm64-msvc/-/resolver-binding-win32-arm64-msvc-1.11.1.tgz",
+ "integrity": "sha512-nRcz5Il4ln0kMhfL8S3hLkxI85BXs3o8EYoattsJNdsX4YUU89iOkVn7g0VHSRxFuVMdM4Q1jEpIId1Ihim/Uw==",
+ "cpu": [
+ "arm64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "win32"
+ ]
+ },
+ "node_modules/@unrs/resolver-binding-win32-ia32-msvc": {
+ "version": "1.11.1",
+ "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-win32-ia32-msvc/-/resolver-binding-win32-ia32-msvc-1.11.1.tgz",
+ "integrity": "sha512-DCEI6t5i1NmAZp6pFonpD5m7i6aFrpofcp4LA2i8IIq60Jyo28hamKBxNrZcyOwVOZkgsRp9O2sXWBWP8MnvIQ==",
+ "cpu": [
+ "ia32"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "win32"
+ ]
+ },
+ "node_modules/@unrs/resolver-binding-win32-x64-msvc": {
+ "version": "1.11.1",
+ "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-win32-x64-msvc/-/resolver-binding-win32-x64-msvc-1.11.1.tgz",
+ "integrity": "sha512-lrW200hZdbfRtztbygyaq/6jP6AKE8qQN2KvPcJ+x7wiD038YtnYtZ82IMNJ69GJibV7bwL3y9FgK+5w/pYt6g==",
+ "cpu": [
+ "x64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "win32"
+ ]
+ },
+ "node_modules/@vercel/og": {
+ "version": "0.8.6",
+ "resolved": "https://registry.npmjs.org/@vercel/og/-/og-0.8.6.tgz",
+ "integrity": "sha512-hBcWIOppZV14bi+eAmCZj8Elj8hVSUZJTpf1lgGBhVD85pervzQ1poM/qYfFUlPraYSZYP+ASg6To5BwYmUSGQ==",
+ "dev": true,
+ "license": "MPL-2.0",
+ "dependencies": {
+ "@resvg/resvg-wasm": "2.4.0",
+ "satori": "0.16.0"
+ },
+ "engines": {
+ "node": ">=16"
+ }
+ },
+ "node_modules/@vitejs/plugin-react": {
+ "version": "6.0.2",
+ "resolved": "https://registry.npmjs.org/@vitejs/plugin-react/-/plugin-react-6.0.2.tgz",
+ "integrity": "sha512-DlSMqo4WhThw4vB8Mpn0Woe9J+Jfq1geJ61AKW0QEgLzGMNwtIMdxbDUzLxcun8W7NbJO0e2Jg/Nxm3cCSVzzg==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@rolldown/pluginutils": "^1.0.0"
+ },
+ "engines": {
+ "node": "^20.19.0 || >=22.12.0"
+ },
+ "peerDependencies": {
+ "@rolldown/plugin-babel": "^0.1.7 || ^0.2.0",
+ "babel-plugin-react-compiler": "^1.0.0",
+ "vite": "^8.0.0"
+ },
+ "peerDependenciesMeta": {
+ "@rolldown/plugin-babel": {
+ "optional": true
+ },
+ "babel-plugin-react-compiler": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/@vitejs/plugin-rsc": {
+ "version": "0.5.26",
+ "resolved": "https://registry.npmjs.org/@vitejs/plugin-rsc/-/plugin-rsc-0.5.26.tgz",
+ "integrity": "sha512-T8W8ODEutblw9qXQB512LDPyv1tAbJRD/Gf0QEGsAoydl4nxEtIrghnhoI9oLY9R+7aw+cLk1ZEltxWHWf4aHw==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@rolldown/pluginutils": "1.0.0-rc.18",
+ "es-module-lexer": "^2.1.0",
+ "estree-walker": "^3.0.3",
+ "magic-string": "^0.30.21",
+ "srvx": "^0.11.15",
+ "strip-literal": "^3.1.0",
+ "turbo-stream": "^3.2.0",
+ "vitefu": "^1.1.3"
+ },
+ "peerDependencies": {
+ "react": "*",
+ "react-dom": "*",
+ "react-server-dom-webpack": "*",
+ "vite": "*"
+ },
+ "peerDependenciesMeta": {
+ "react-server-dom-webpack": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/@vitejs/plugin-rsc/node_modules/@rolldown/pluginutils": {
+ "version": "1.0.0-rc.18",
+ "resolved": "https://registry.npmjs.org/@rolldown/pluginutils/-/pluginutils-1.0.0-rc.18.tgz",
+ "integrity": "sha512-CUY5Mnhe64xQBGZEEXQ5WyZwsc1JU3vAZLIxtrsBt3LO6UOb+C8GunVKqe9sT8NeWb4lqSaoJtp2xo6GxT1MNw==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/@webassemblyjs/ast": {
+ "version": "1.14.1",
+ "resolved": "https://registry.npmjs.org/@webassemblyjs/ast/-/ast-1.14.1.tgz",
+ "integrity": "sha512-nuBEDgQfm1ccRp/8bCQrx1frohyufl4JlbMMZ4P1wpeOfDhF6FQkxZJ1b/e+PLwr6X1Nhw6OLme5usuBWYBvuQ==",
+ "dev": true,
+ "license": "MIT",
+ "peer": true,
+ "dependencies": {
+ "@webassemblyjs/helper-numbers": "1.13.2",
+ "@webassemblyjs/helper-wasm-bytecode": "1.13.2"
+ }
+ },
+ "node_modules/@webassemblyjs/floating-point-hex-parser": {
+ "version": "1.13.2",
+ "resolved": "https://registry.npmjs.org/@webassemblyjs/floating-point-hex-parser/-/floating-point-hex-parser-1.13.2.tgz",
+ "integrity": "sha512-6oXyTOzbKxGH4steLbLNOu71Oj+C8Lg34n6CqRvqfS2O71BxY6ByfMDRhBytzknj9yGUPVJ1qIKhRlAwO1AovA==",
+ "dev": true,
+ "license": "MIT",
+ "peer": true
+ },
+ "node_modules/@webassemblyjs/helper-api-error": {
+ "version": "1.13.2",
+ "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-api-error/-/helper-api-error-1.13.2.tgz",
+ "integrity": "sha512-U56GMYxy4ZQCbDZd6JuvvNV/WFildOjsaWD3Tzzvmw/mas3cXzRJPMjP83JqEsgSbyrmaGjBfDtV7KDXV9UzFQ==",
+ "dev": true,
+ "license": "MIT",
+ "peer": true
+ },
+ "node_modules/@webassemblyjs/helper-buffer": {
+ "version": "1.14.1",
+ "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-buffer/-/helper-buffer-1.14.1.tgz",
+ "integrity": "sha512-jyH7wtcHiKssDtFPRB+iQdxlDf96m0E39yb0k5uJVhFGleZFoNw1c4aeIcVUPPbXUVJ94wwnMOAqUHyzoEPVMA==",
+ "dev": true,
+ "license": "MIT",
+ "peer": true
+ },
+ "node_modules/@webassemblyjs/helper-numbers": {
+ "version": "1.13.2",
+ "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-numbers/-/helper-numbers-1.13.2.tgz",
+ "integrity": "sha512-FE8aCmS5Q6eQYcV3gI35O4J789wlQA+7JrqTTpJqn5emA4U2hvwJmvFRC0HODS+3Ye6WioDklgd6scJ3+PLnEA==",
+ "dev": true,
+ "license": "MIT",
+ "peer": true,
+ "dependencies": {
+ "@webassemblyjs/floating-point-hex-parser": "1.13.2",
+ "@webassemblyjs/helper-api-error": "1.13.2",
+ "@xtuc/long": "4.2.2"
+ }
+ },
+ "node_modules/@webassemblyjs/helper-wasm-bytecode": {
+ "version": "1.13.2",
+ "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-wasm-bytecode/-/helper-wasm-bytecode-1.13.2.tgz",
+ "integrity": "sha512-3QbLKy93F0EAIXLh0ogEVR6rOubA9AoZ+WRYhNbFyuB70j3dRdwH9g+qXhLAO0kiYGlg3TxDV+I4rQTr/YNXkA==",
+ "dev": true,
+ "license": "MIT",
+ "peer": true
+ },
+ "node_modules/@webassemblyjs/helper-wasm-section": {
+ "version": "1.14.1",
+ "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-wasm-section/-/helper-wasm-section-1.14.1.tgz",
+ "integrity": "sha512-ds5mXEqTJ6oxRoqjhWDU83OgzAYjwsCV8Lo/N+oRsNDmx/ZDpqalmrtgOMkHwxsG0iI//3BwWAErYRHtgn0dZw==",
+ "dev": true,
+ "license": "MIT",
+ "peer": true,
+ "dependencies": {
+ "@webassemblyjs/ast": "1.14.1",
+ "@webassemblyjs/helper-buffer": "1.14.1",
+ "@webassemblyjs/helper-wasm-bytecode": "1.13.2",
+ "@webassemblyjs/wasm-gen": "1.14.1"
+ }
+ },
+ "node_modules/@webassemblyjs/ieee754": {
+ "version": "1.13.2",
+ "resolved": "https://registry.npmjs.org/@webassemblyjs/ieee754/-/ieee754-1.13.2.tgz",
+ "integrity": "sha512-4LtOzh58S/5lX4ITKxnAK2USuNEvpdVV9AlgGQb8rJDHaLeHciwG4zlGr0j/SNWlr7x3vO1lDEsuePvtcDNCkw==",
+ "dev": true,
+ "license": "MIT",
+ "peer": true,
+ "dependencies": {
+ "@xtuc/ieee754": "^1.2.0"
+ }
+ },
+ "node_modules/@webassemblyjs/leb128": {
+ "version": "1.13.2",
+ "resolved": "https://registry.npmjs.org/@webassemblyjs/leb128/-/leb128-1.13.2.tgz",
+ "integrity": "sha512-Lde1oNoIdzVzdkNEAWZ1dZ5orIbff80YPdHx20mrHwHrVNNTjNr8E3xz9BdpcGqRQbAEa+fkrCb+fRFTl/6sQw==",
+ "dev": true,
+ "license": "Apache-2.0",
+ "peer": true,
+ "dependencies": {
+ "@xtuc/long": "4.2.2"
+ }
+ },
+ "node_modules/@webassemblyjs/utf8": {
+ "version": "1.13.2",
+ "resolved": "https://registry.npmjs.org/@webassemblyjs/utf8/-/utf8-1.13.2.tgz",
+ "integrity": "sha512-3NQWGjKTASY1xV5m7Hr0iPeXD9+RDobLll3T9d2AO+g3my8xy5peVyjSag4I50mR1bBSN/Ct12lo+R9tJk0NZQ==",
+ "dev": true,
+ "license": "MIT",
+ "peer": true
+ },
+ "node_modules/@webassemblyjs/wasm-edit": {
+ "version": "1.14.1",
+ "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-edit/-/wasm-edit-1.14.1.tgz",
+ "integrity": "sha512-RNJUIQH/J8iA/1NzlE4N7KtyZNHi3w7at7hDjvRNm5rcUXa00z1vRz3glZoULfJ5mpvYhLybmVcwcjGrC1pRrQ==",
+ "dev": true,
+ "license": "MIT",
+ "peer": true,
+ "dependencies": {
+ "@webassemblyjs/ast": "1.14.1",
+ "@webassemblyjs/helper-buffer": "1.14.1",
+ "@webassemblyjs/helper-wasm-bytecode": "1.13.2",
+ "@webassemblyjs/helper-wasm-section": "1.14.1",
+ "@webassemblyjs/wasm-gen": "1.14.1",
+ "@webassemblyjs/wasm-opt": "1.14.1",
+ "@webassemblyjs/wasm-parser": "1.14.1",
+ "@webassemblyjs/wast-printer": "1.14.1"
+ }
+ },
+ "node_modules/@webassemblyjs/wasm-gen": {
+ "version": "1.14.1",
+ "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-gen/-/wasm-gen-1.14.1.tgz",
+ "integrity": "sha512-AmomSIjP8ZbfGQhumkNvgC33AY7qtMCXnN6bL2u2Js4gVCg8fp735aEiMSBbDR7UQIj90n4wKAFUSEd0QN2Ukg==",
+ "dev": true,
+ "license": "MIT",
+ "peer": true,
+ "dependencies": {
+ "@webassemblyjs/ast": "1.14.1",
+ "@webassemblyjs/helper-wasm-bytecode": "1.13.2",
+ "@webassemblyjs/ieee754": "1.13.2",
+ "@webassemblyjs/leb128": "1.13.2",
+ "@webassemblyjs/utf8": "1.13.2"
+ }
+ },
+ "node_modules/@webassemblyjs/wasm-opt": {
+ "version": "1.14.1",
+ "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-opt/-/wasm-opt-1.14.1.tgz",
+ "integrity": "sha512-PTcKLUNvBqnY2U6E5bdOQcSM+oVP/PmrDY9NzowJjislEjwP/C4an2303MCVS2Mg9d3AJpIGdUFIQQWbPds0Sw==",
+ "dev": true,
+ "license": "MIT",
+ "peer": true,
+ "dependencies": {
+ "@webassemblyjs/ast": "1.14.1",
+ "@webassemblyjs/helper-buffer": "1.14.1",
+ "@webassemblyjs/wasm-gen": "1.14.1",
+ "@webassemblyjs/wasm-parser": "1.14.1"
+ }
+ },
+ "node_modules/@webassemblyjs/wasm-parser": {
+ "version": "1.14.1",
+ "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-parser/-/wasm-parser-1.14.1.tgz",
+ "integrity": "sha512-JLBl+KZ0R5qB7mCnud/yyX08jWFw5MsoalJ1pQ4EdFlgj9VdXKGuENGsiCIjegI1W7p91rUlcB/LB5yRJKNTcQ==",
+ "dev": true,
+ "license": "MIT",
+ "peer": true,
+ "dependencies": {
+ "@webassemblyjs/ast": "1.14.1",
+ "@webassemblyjs/helper-api-error": "1.13.2",
+ "@webassemblyjs/helper-wasm-bytecode": "1.13.2",
+ "@webassemblyjs/ieee754": "1.13.2",
+ "@webassemblyjs/leb128": "1.13.2",
+ "@webassemblyjs/utf8": "1.13.2"
+ }
+ },
+ "node_modules/@webassemblyjs/wast-printer": {
+ "version": "1.14.1",
+ "resolved": "https://registry.npmjs.org/@webassemblyjs/wast-printer/-/wast-printer-1.14.1.tgz",
+ "integrity": "sha512-kPSSXE6De1XOR820C90RIo2ogvZG+c3KiHzqUoO/F34Y2shGzesfqv7o57xrxovZJH/MetF5UjroJ/R/3isoiw==",
+ "dev": true,
+ "license": "MIT",
+ "peer": true,
+ "dependencies": {
+ "@webassemblyjs/ast": "1.14.1",
+ "@xtuc/long": "4.2.2"
+ }
+ },
+ "node_modules/@xtuc/ieee754": {
+ "version": "1.2.0",
+ "resolved": "https://registry.npmjs.org/@xtuc/ieee754/-/ieee754-1.2.0.tgz",
+ "integrity": "sha512-DX8nKgqcGwsc0eJSqYt5lwP4DH5FlHnmuWWBRy7X0NcaGR0ZtuyeESgMwTYVEtxmsNGY+qit4QYT/MIYTOTPeA==",
+ "dev": true,
+ "license": "BSD-3-Clause",
+ "peer": true
+ },
+ "node_modules/@xtuc/long": {
+ "version": "4.2.2",
+ "resolved": "https://registry.npmjs.org/@xtuc/long/-/long-4.2.2.tgz",
+ "integrity": "sha512-NuHqBY1PB/D8xU6s/thBgOAiAP7HOYDQ32+BFZILJ8ivkUkAHQnWfn6WhL79Owj1qmUnoN/YPhktdIoucipkAQ==",
+ "dev": true,
+ "license": "Apache-2.0",
+ "peer": true
+ },
+ "node_modules/acorn": {
+ "version": "8.16.0",
+ "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.16.0.tgz",
+ "integrity": "sha512-UVJyE9MttOsBQIDKw1skb9nAwQuR5wuGD3+82K6JgJlm/Y+KI92oNsMNGZCYdDsVtRHSak0pcV5Dno5+4jh9sw==",
+ "dev": true,
+ "license": "MIT",
+ "bin": {
+ "acorn": "bin/acorn"
+ },
+ "engines": {
+ "node": ">=0.4.0"
+ }
+ },
+ "node_modules/acorn-import-phases": {
+ "version": "1.0.4",
+ "resolved": "https://registry.npmjs.org/acorn-import-phases/-/acorn-import-phases-1.0.4.tgz",
+ "integrity": "sha512-wKmbr/DDiIXzEOiWrTTUcDm24kQ2vGfZQvM2fwg2vXqR5uW6aapr7ObPtj1th32b9u90/Pf4AItvdTh42fBmVQ==",
+ "dev": true,
+ "license": "MIT",
+ "peer": true,
+ "engines": {
+ "node": ">=10.13.0"
+ },
+ "peerDependencies": {
+ "acorn": "^8.14.0"
+ }
+ },
+ "node_modules/acorn-jsx": {
+ "version": "5.3.2",
+ "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.2.tgz",
+ "integrity": "sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==",
+ "dev": true,
+ "license": "MIT",
+ "peerDependencies": {
+ "acorn": "^6.0.0 || ^7.0.0 || ^8.0.0"
+ }
+ },
+ "node_modules/acorn-loose": {
+ "version": "8.5.2",
+ "resolved": "https://registry.npmjs.org/acorn-loose/-/acorn-loose-8.5.2.tgz",
+ "integrity": "sha512-PPvV6g8UGMGgjrMu+n/f9E/tCSkNQ2Y97eFvuVdJfG11+xdIeDcLyNdC8SHcrHbRqkfwLASdplyR6B6sKM1U4A==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "acorn": "^8.15.0"
+ },
+ "engines": {
+ "node": ">=0.4.0"
+ }
+ },
+ "node_modules/ajv": {
+ "version": "6.15.0",
+ "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.15.0.tgz",
+ "integrity": "sha512-fgFx7Hfoq60ytK2c7DhnF8jIvzYgOMxfugjLOSMHjLIPgenqa7S7oaagATUq99mV6IYvN2tRmC0wnTYX6iPbMw==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "fast-deep-equal": "^3.1.1",
+ "fast-json-stable-stringify": "^2.0.0",
+ "json-schema-traverse": "^0.4.1",
+ "uri-js": "^4.2.2"
+ },
+ "funding": {
+ "type": "github",
+ "url": "https://github.com/sponsors/epoberezkin"
+ }
+ },
+ "node_modules/ajv-formats": {
+ "version": "2.1.1",
+ "resolved": "https://registry.npmjs.org/ajv-formats/-/ajv-formats-2.1.1.tgz",
+ "integrity": "sha512-Wx0Kx52hxE7C18hkMEggYlEifqWZtYaRgouJor+WMdPnQyEK13vgEWyVNup7SoeeoLMsr4kf5h6dOW11I15MUA==",
+ "dev": true,
+ "license": "MIT",
+ "peer": true,
+ "dependencies": {
+ "ajv": "^8.0.0"
+ },
+ "peerDependencies": {
+ "ajv": "^8.0.0"
+ },
+ "peerDependenciesMeta": {
+ "ajv": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/ajv-formats/node_modules/ajv": {
+ "version": "8.20.0",
+ "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.20.0.tgz",
+ "integrity": "sha512-Thbli+OlOj+iMPYFBVBfJ3OmCAnaSyNn4M1vz9T6Gka5Jt9ba/HIR56joy65tY6kx/FCF5VXNB819Y7/GUrBGA==",
+ "dev": true,
+ "license": "MIT",
+ "peer": true,
+ "dependencies": {
+ "fast-deep-equal": "^3.1.3",
+ "fast-uri": "^3.0.1",
+ "json-schema-traverse": "^1.0.0",
+ "require-from-string": "^2.0.2"
+ },
+ "funding": {
+ "type": "github",
+ "url": "https://github.com/sponsors/epoberezkin"
+ }
+ },
+ "node_modules/ajv-formats/node_modules/json-schema-traverse": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz",
+ "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==",
+ "dev": true,
+ "license": "MIT",
+ "peer": true
+ },
+ "node_modules/ansi-styles": {
+ "version": "4.3.0",
+ "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz",
+ "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "color-convert": "^2.0.1"
+ },
+ "engines": {
+ "node": ">=8"
+ },
+ "funding": {
+ "url": "https://github.com/chalk/ansi-styles?sponsor=1"
+ }
+ },
+ "node_modules/argparse": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz",
+ "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==",
+ "dev": true,
+ "license": "Python-2.0"
+ },
+ "node_modules/aria-query": {
+ "version": "5.3.2",
+ "resolved": "https://registry.npmjs.org/aria-query/-/aria-query-5.3.2.tgz",
+ "integrity": "sha512-COROpnaoap1E2F000S62r6A60uHZnmlvomhfyT2DlTcrY1OrBKn2UhH7qn5wTC9zMvD0AY7csdPSNwKP+7WiQw==",
+ "dev": true,
+ "license": "Apache-2.0",
+ "engines": {
+ "node": ">= 0.4"
+ }
+ },
+ "node_modules/array-buffer-byte-length": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/array-buffer-byte-length/-/array-buffer-byte-length-1.0.2.tgz",
+ "integrity": "sha512-LHE+8BuR7RYGDKvnrmcuSq3tDcKv9OFEXQt/HpbZhY7V6h0zlUXutnAD82GiFx9rdieCMjkvtcsPqBwgUl1Iiw==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "call-bound": "^1.0.3",
+ "is-array-buffer": "^3.0.5"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/array-includes": {
+ "version": "3.1.9",
+ "resolved": "https://registry.npmjs.org/array-includes/-/array-includes-3.1.9.tgz",
+ "integrity": "sha512-FmeCCAenzH0KH381SPT5FZmiA/TmpndpcaShhfgEN9eCVjnFBqq3l1xrI42y8+PPLI6hypzou4GXw00WHmPBLQ==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "call-bind": "^1.0.8",
+ "call-bound": "^1.0.4",
+ "define-properties": "^1.2.1",
+ "es-abstract": "^1.24.0",
+ "es-object-atoms": "^1.1.1",
+ "get-intrinsic": "^1.3.0",
+ "is-string": "^1.1.1",
+ "math-intrinsics": "^1.1.0"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/array.prototype.findlast": {
+ "version": "1.2.5",
+ "resolved": "https://registry.npmjs.org/array.prototype.findlast/-/array.prototype.findlast-1.2.5.tgz",
+ "integrity": "sha512-CVvd6FHg1Z3POpBLxO6E6zr+rSKEQ9L6rZHAaY7lLfhKsWYUBBOuMs0e9o24oopj6H+geRCX0YJ+TJLBK2eHyQ==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "call-bind": "^1.0.7",
+ "define-properties": "^1.2.1",
+ "es-abstract": "^1.23.2",
+ "es-errors": "^1.3.0",
+ "es-object-atoms": "^1.0.0",
+ "es-shim-unscopables": "^1.0.2"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/array.prototype.findlastindex": {
+ "version": "1.2.6",
+ "resolved": "https://registry.npmjs.org/array.prototype.findlastindex/-/array.prototype.findlastindex-1.2.6.tgz",
+ "integrity": "sha512-F/TKATkzseUExPlfvmwQKGITM3DGTK+vkAsCZoDc5daVygbJBnjEUCbgkAvVFsgfXfX4YIqZ/27G3k3tdXrTxQ==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "call-bind": "^1.0.8",
+ "call-bound": "^1.0.4",
+ "define-properties": "^1.2.1",
+ "es-abstract": "^1.23.9",
+ "es-errors": "^1.3.0",
+ "es-object-atoms": "^1.1.1",
+ "es-shim-unscopables": "^1.1.0"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/array.prototype.flat": {
+ "version": "1.3.3",
+ "resolved": "https://registry.npmjs.org/array.prototype.flat/-/array.prototype.flat-1.3.3.tgz",
+ "integrity": "sha512-rwG/ja1neyLqCuGZ5YYrznA62D4mZXg0i1cIskIUKSiqF3Cje9/wXAls9B9s1Wa2fomMsIv8czB8jZcPmxCXFg==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "call-bind": "^1.0.8",
+ "define-properties": "^1.2.1",
+ "es-abstract": "^1.23.5",
+ "es-shim-unscopables": "^1.0.2"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/array.prototype.flatmap": {
+ "version": "1.3.3",
+ "resolved": "https://registry.npmjs.org/array.prototype.flatmap/-/array.prototype.flatmap-1.3.3.tgz",
+ "integrity": "sha512-Y7Wt51eKJSyi80hFrJCePGGNo5ktJCslFuboqJsbf57CCPcm5zztluPlc4/aD8sWsKvlwatezpV4U1efk8kpjg==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "call-bind": "^1.0.8",
+ "define-properties": "^1.2.1",
+ "es-abstract": "^1.23.5",
+ "es-shim-unscopables": "^1.0.2"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/array.prototype.tosorted": {
+ "version": "1.1.4",
+ "resolved": "https://registry.npmjs.org/array.prototype.tosorted/-/array.prototype.tosorted-1.1.4.tgz",
+ "integrity": "sha512-p6Fx8B7b7ZhL/gmUsAy0D15WhvDccw3mnGNbZpi3pmeJdxtWsj2jEaI4Y6oo3XiHfzuSgPwKc04MYt6KgvC/wA==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "call-bind": "^1.0.7",
+ "define-properties": "^1.2.1",
+ "es-abstract": "^1.23.3",
+ "es-errors": "^1.3.0",
+ "es-shim-unscopables": "^1.0.2"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ }
+ },
+ "node_modules/arraybuffer.prototype.slice": {
+ "version": "1.0.4",
+ "resolved": "https://registry.npmjs.org/arraybuffer.prototype.slice/-/arraybuffer.prototype.slice-1.0.4.tgz",
+ "integrity": "sha512-BNoCY6SXXPQ7gF2opIP4GBE+Xw7U+pHMYKuzjgCN3GwiaIR09UUeKfheyIry77QtrCBlC0KK0q5/TER/tYh3PQ==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "array-buffer-byte-length": "^1.0.1",
+ "call-bind": "^1.0.8",
+ "define-properties": "^1.2.1",
+ "es-abstract": "^1.23.5",
+ "es-errors": "^1.3.0",
+ "get-intrinsic": "^1.2.6",
+ "is-array-buffer": "^3.0.4"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/ast-types-flow": {
+ "version": "0.0.8",
+ "resolved": "https://registry.npmjs.org/ast-types-flow/-/ast-types-flow-0.0.8.tgz",
+ "integrity": "sha512-OH/2E5Fg20h2aPrbe+QL8JZQFko0YZaF+j4mnQ7BGhfavO7OpSLa8a0y9sBwomHdSbkhTS8TQNayBfnW5DwbvQ==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/async-function": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/async-function/-/async-function-1.0.0.tgz",
+ "integrity": "sha512-hsU18Ae8CDTR6Kgu9DYf0EbCr/a5iGL0rytQDobUcdpYOKokk8LEjVphnXkDkgpi0wYVsqrXuP0bZxJaTqdgoA==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">= 0.4"
+ }
+ },
+ "node_modules/available-typed-arrays": {
+ "version": "1.0.7",
+ "resolved": "https://registry.npmjs.org/available-typed-arrays/-/available-typed-arrays-1.0.7.tgz",
+ "integrity": "sha512-wvUjBtSGN7+7SjNpq/9M2Tg350UZD3q62IFZLbRAR1bSMlCo1ZaeW+BJ+D090e4hIIZLBcTDWe4Mh4jvUDajzQ==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "possible-typed-array-names": "^1.0.0"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/axe-core": {
+ "version": "4.11.4",
+ "resolved": "https://registry.npmjs.org/axe-core/-/axe-core-4.11.4.tgz",
+ "integrity": "sha512-KunSNx+TVpkAw/6ULfhnx+HWRecjqZGTOyquAoWHYLRSdK1tB5Ihce1ZW+UY3fj33bYAFWPu7W/GRSmmrCGuxA==",
+ "dev": true,
+ "license": "MPL-2.0",
+ "engines": {
+ "node": ">=4"
+ }
+ },
+ "node_modules/axobject-query": {
+ "version": "4.1.0",
+ "resolved": "https://registry.npmjs.org/axobject-query/-/axobject-query-4.1.0.tgz",
+ "integrity": "sha512-qIj0G9wZbMGNLjLmg1PT6v2mE9AH2zlnADJD/2tC6E00hgmhUOfEB6greHPAfLRSufHqROIUTkw6E+M3lH0PTQ==",
+ "dev": true,
+ "license": "Apache-2.0",
+ "engines": {
+ "node": ">= 0.4"
+ }
+ },
+ "node_modules/balanced-match": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz",
+ "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/base64-js": {
+ "version": "0.0.8",
+ "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-0.0.8.tgz",
+ "integrity": "sha512-3XSA2cR/h/73EzlXXdU6YNycmYI7+kicTxks4eJg2g39biHR84slg2+des+p7iHYhbRg/udIS4TD53WabcOUkw==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">= 0.4"
+ }
+ },
+ "node_modules/baseline-browser-mapping": {
+ "version": "2.10.30",
+ "resolved": "https://registry.npmjs.org/baseline-browser-mapping/-/baseline-browser-mapping-2.10.30.tgz",
+ "integrity": "sha512-xjOFN16Ha1+Rz4nFYKqHU/LSB+gx/Vi3yQLX7r7sAW+Wa+8hhF2h4pvqTrTMc8+WcDBEunnUurr46Jvv0jk3Vg==",
+ "license": "Apache-2.0",
+ "bin": {
+ "baseline-browser-mapping": "dist/cli.cjs"
+ },
+ "engines": {
+ "node": ">=6.0.0"
+ }
+ },
+ "node_modules/blake3-wasm": {
+ "version": "2.1.5",
+ "resolved": "https://registry.npmjs.org/blake3-wasm/-/blake3-wasm-2.1.5.tgz",
+ "integrity": "sha512-F1+K8EbfOZE49dtoPtmxUQrpXaBIl3ICvasLh+nJta0xkz+9kF/7uet9fLnwKqhDrmj6g+6K3Tw9yQPUg2ka5g==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/brace-expansion": {
+ "version": "1.1.14",
+ "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.14.tgz",
+ "integrity": "sha512-MWPGfDxnyzKU7rNOW9SP/c50vi3xrmrua/+6hfPbCS2ABNWfx24vPidzvC7krjU/RTo235sV776ymlsMtGKj8g==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "balanced-match": "^1.0.0",
+ "concat-map": "0.0.1"
+ }
+ },
+ "node_modules/braces": {
+ "version": "3.0.3",
+ "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.3.tgz",
+ "integrity": "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "fill-range": "^7.1.1"
+ },
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/browserslist": {
+ "version": "4.28.2",
+ "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.28.2.tgz",
+ "integrity": "sha512-48xSriZYYg+8qXna9kwqjIVzuQxi+KYWp2+5nCYnYKPTr0LvD89Jqk2Or5ogxz0NUMfIjhh2lIUX/LyX9B4oIg==",
+ "dev": true,
+ "funding": [
+ {
+ "type": "opencollective",
+ "url": "https://opencollective.com/browserslist"
+ },
+ {
+ "type": "tidelift",
+ "url": "https://tidelift.com/funding/github/npm/browserslist"
+ },
+ {
+ "type": "github",
+ "url": "https://github.com/sponsors/ai"
+ }
+ ],
+ "license": "MIT",
+ "dependencies": {
+ "baseline-browser-mapping": "^2.10.12",
+ "caniuse-lite": "^1.0.30001782",
+ "electron-to-chromium": "^1.5.328",
+ "node-releases": "^2.0.36",
+ "update-browserslist-db": "^1.2.3"
+ },
+ "bin": {
+ "browserslist": "cli.js"
+ },
+ "engines": {
+ "node": "^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7"
+ }
+ },
+ "node_modules/buffer-from": {
+ "version": "1.1.2",
+ "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.2.tgz",
+ "integrity": "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/call-bind": {
+ "version": "1.0.9",
+ "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.9.tgz",
+ "integrity": "sha512-a/hy+pNsFUTR+Iz8TCJvXudKVLAnz/DyeSUo10I5yvFDQJBFU2s9uqQpoSrJlroHUKoKqzg+epxyP9lqFdzfBQ==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "call-bind-apply-helpers": "^1.0.2",
+ "es-define-property": "^1.0.1",
+ "get-intrinsic": "^1.3.0",
+ "set-function-length": "^1.2.2"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/call-bind-apply-helpers": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/call-bind-apply-helpers/-/call-bind-apply-helpers-1.0.2.tgz",
+ "integrity": "sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "es-errors": "^1.3.0",
+ "function-bind": "^1.1.2"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ }
+ },
+ "node_modules/call-bound": {
+ "version": "1.0.4",
+ "resolved": "https://registry.npmjs.org/call-bound/-/call-bound-1.0.4.tgz",
+ "integrity": "sha512-+ys997U96po4Kx/ABpBCqhA9EuxJaQWDQg7295H4hBphv3IZg0boBKuwYpt4YXp6MZ5AmZQnU/tyMTlRpaSejg==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "call-bind-apply-helpers": "^1.0.2",
+ "get-intrinsic": "^1.3.0"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/callsites": {
+ "version": "3.1.0",
+ "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz",
+ "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=6"
+ }
+ },
+ "node_modules/camelize": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/camelize/-/camelize-1.0.1.tgz",
+ "integrity": "sha512-dU+Tx2fsypxTgtLoE36npi3UqcjSSMNYfkqgmoEhtZrraP5VWq0K7FkWVTYa8eMPtnU/G2txVsfdCJTn9uzpuQ==",
+ "dev": true,
+ "license": "MIT",
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/caniuse-lite": {
+ "version": "1.0.30001793",
+ "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001793.tgz",
+ "integrity": "sha512-iwSsYWaCOoh26cV8NwNRViHlrfUvYsHDfRVcbtmw0Kg6PJIZZXwMkj1442FYLBGkeUf1juAsU3DTfxW579mrPA==",
+ "funding": [
+ {
+ "type": "opencollective",
+ "url": "https://opencollective.com/browserslist"
+ },
+ {
+ "type": "tidelift",
+ "url": "https://tidelift.com/funding/github/npm/caniuse-lite"
+ },
+ {
+ "type": "github",
+ "url": "https://github.com/sponsors/ai"
+ }
+ ],
+ "license": "CC-BY-4.0"
+ },
+ "node_modules/chalk": {
+ "version": "4.1.2",
+ "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz",
+ "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "ansi-styles": "^4.1.0",
+ "supports-color": "^7.1.0"
+ },
+ "engines": {
+ "node": ">=10"
+ },
+ "funding": {
+ "url": "https://github.com/chalk/chalk?sponsor=1"
+ }
+ },
+ "node_modules/chrome-trace-event": {
+ "version": "1.0.4",
+ "resolved": "https://registry.npmjs.org/chrome-trace-event/-/chrome-trace-event-1.0.4.tgz",
+ "integrity": "sha512-rNjApaLzuwaOTjCiT8lSDdGN1APCiqkChLMJxJPWLunPAt5fy8xgU9/jNOchV84wfIxrA0lRQB7oCT8jrn/wrQ==",
+ "dev": true,
+ "license": "MIT",
+ "peer": true,
+ "engines": {
+ "node": ">=6.0"
+ }
+ },
+ "node_modules/client-only": {
+ "version": "0.0.1",
+ "resolved": "https://registry.npmjs.org/client-only/-/client-only-0.0.1.tgz",
+ "integrity": "sha512-IV3Ou0jSMzZrd3pZ48nLkT9DA7Ag1pnPzaiQhpW7c3RbcqqzvzzVu+L8gfqMp/8IM2MQtSiqaCxrrcfu8I8rMA==",
+ "license": "MIT"
+ },
+ "node_modules/color-convert": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz",
+ "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "color-name": "~1.1.4"
+ },
+ "engines": {
+ "node": ">=7.0.0"
+ }
+ },
+ "node_modules/color-name": {
+ "version": "1.1.4",
+ "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz",
+ "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/commander": {
+ "version": "2.20.3",
+ "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz",
+ "integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==",
+ "dev": true,
+ "license": "MIT",
+ "peer": true
+ },
+ "node_modules/concat-map": {
+ "version": "0.0.1",
+ "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz",
+ "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/convert-source-map": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-2.0.0.tgz",
+ "integrity": "sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/cookie": {
+ "version": "1.1.1",
+ "resolved": "https://registry.npmjs.org/cookie/-/cookie-1.1.1.tgz",
+ "integrity": "sha512-ei8Aos7ja0weRpFzJnEA9UHJ/7XQmqglbRwnf2ATjcB9Wq874VKH9kfjjirM6UhU2/E5fFYadylyhFldcqSidQ==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=18"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/express"
+ }
+ },
+ "node_modules/cross-spawn": {
+ "version": "7.0.6",
+ "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.6.tgz",
+ "integrity": "sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "path-key": "^3.1.0",
+ "shebang-command": "^2.0.0",
+ "which": "^2.0.1"
+ },
+ "engines": {
+ "node": ">= 8"
+ }
+ },
+ "node_modules/css-background-parser": {
+ "version": "0.1.0",
+ "resolved": "https://registry.npmjs.org/css-background-parser/-/css-background-parser-0.1.0.tgz",
+ "integrity": "sha512-2EZLisiZQ+7m4wwur/qiYJRniHX4K5Tc9w93MT3AS0WS1u5kaZ4FKXlOTBhOjc+CgEgPiGY+fX1yWD8UwpEqUA==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/css-box-shadow": {
+ "version": "1.0.0-3",
+ "resolved": "https://registry.npmjs.org/css-box-shadow/-/css-box-shadow-1.0.0-3.tgz",
+ "integrity": "sha512-9jaqR6e7Ohds+aWwmhe6wILJ99xYQbfmK9QQB9CcMjDbTxPZjwEmUQpU91OG05Xgm8BahT5fW+svbsQGjS/zPg==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/css-color-keywords": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/css-color-keywords/-/css-color-keywords-1.0.0.tgz",
+ "integrity": "sha512-FyyrDHZKEjXDpNJYvVsV960FiqQyXc/LlYmsxl2BcdMb2WPx0OGRVgTg55rPSyLSNMqP52R9r8geSp7apN3Ofg==",
+ "dev": true,
+ "license": "ISC",
+ "engines": {
+ "node": ">=4"
+ }
+ },
+ "node_modules/css-gradient-parser": {
+ "version": "0.0.16",
+ "resolved": "https://registry.npmjs.org/css-gradient-parser/-/css-gradient-parser-0.0.16.tgz",
+ "integrity": "sha512-3O5QdqgFRUbXvK1x5INf1YkBz1UKSWqrd63vWsum8MNHDBYD5urm3QtxZbKU259OrEXNM26lP/MPY3d1IGkBgA==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=16"
+ }
+ },
+ "node_modules/css-to-react-native": {
+ "version": "3.2.0",
+ "resolved": "https://registry.npmjs.org/css-to-react-native/-/css-to-react-native-3.2.0.tgz",
+ "integrity": "sha512-e8RKaLXMOFii+02mOlqwjbD00KSEKqblnpO9e++1aXS1fPQOpS1YoqdVHBqPjHNoxeF2mimzVqawm2KCbEdtHQ==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "camelize": "^1.0.0",
+ "css-color-keywords": "^1.0.0",
+ "postcss-value-parser": "^4.0.2"
+ }
+ },
+ "node_modules/csstype": {
+ "version": "3.2.3",
+ "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.2.3.tgz",
+ "integrity": "sha512-z1HGKcYy2xA8AGQfwrn0PAy+PB7X/GSj3UVJW9qKyn43xWa+gl5nXmU4qqLMRzWVLFC8KusUX8T/0kCiOYpAIQ==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/damerau-levenshtein": {
+ "version": "1.0.8",
+ "resolved": "https://registry.npmjs.org/damerau-levenshtein/-/damerau-levenshtein-1.0.8.tgz",
+ "integrity": "sha512-sdQSFB7+llfUcQHUQO3+B8ERRj0Oa4w9POWMI/puGtuf7gFywGmkaLCElnudfTiKZV+NvHqL0ifzdrI8Ro7ESA==",
+ "dev": true,
+ "license": "BSD-2-Clause"
+ },
+ "node_modules/data-view-buffer": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/data-view-buffer/-/data-view-buffer-1.0.2.tgz",
+ "integrity": "sha512-EmKO5V3OLXh1rtK2wgXRansaK1/mtVdTUEiEI0W8RkvgT05kfxaH29PliLnpLP73yYO6142Q72QNa8Wx/A5CqQ==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "call-bound": "^1.0.3",
+ "es-errors": "^1.3.0",
+ "is-data-view": "^1.0.2"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/data-view-byte-length": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/data-view-byte-length/-/data-view-byte-length-1.0.2.tgz",
+ "integrity": "sha512-tuhGbE6CfTM9+5ANGf+oQb72Ky/0+s3xKUpHvShfiz2RxMFgFPjsXuRLBVMtvMs15awe45SRb83D6wH4ew6wlQ==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "call-bound": "^1.0.3",
+ "es-errors": "^1.3.0",
+ "is-data-view": "^1.0.2"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/inspect-js"
+ }
+ },
+ "node_modules/data-view-byte-offset": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/data-view-byte-offset/-/data-view-byte-offset-1.0.1.tgz",
+ "integrity": "sha512-BS8PfmtDGnrgYdOonGZQdLZslWIeCGFP9tpan0hi1Co2Zr2NKADsvGYA8XxuG/4UWgJ6Cjtv+YJnB6MM69QGlQ==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "call-bound": "^1.0.2",
+ "es-errors": "^1.3.0",
+ "is-data-view": "^1.0.1"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/debug": {
+ "version": "4.4.3",
+ "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.3.tgz",
+ "integrity": "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "ms": "^2.1.3"
+ },
+ "engines": {
+ "node": ">=6.0"
+ },
+ "peerDependenciesMeta": {
+ "supports-color": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/deep-is": {
+ "version": "0.1.4",
+ "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.4.tgz",
+ "integrity": "sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/define-data-property": {
+ "version": "1.1.4",
+ "resolved": "https://registry.npmjs.org/define-data-property/-/define-data-property-1.1.4.tgz",
+ "integrity": "sha512-rBMvIzlpA8v6E+SJZoo++HAYqsLrkg7MSfIinMPFhmkorw7X+dOXVJQs+QT69zGkzMyfDnIMN2Wid1+NbL3T+A==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "es-define-property": "^1.0.0",
+ "es-errors": "^1.3.0",
+ "gopd": "^1.0.1"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/define-properties": {
+ "version": "1.2.1",
+ "resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.2.1.tgz",
+ "integrity": "sha512-8QmQKqEASLd5nx0U1B1okLElbUuuttJ/AnYmRXbbbGDWh6uS208EjD4Xqq/I9wK7u0v6O08XhTWnt5XtEbR6Dg==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "define-data-property": "^1.0.1",
+ "has-property-descriptors": "^1.0.0",
+ "object-keys": "^1.1.1"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/detect-libc": {
+ "version": "2.1.2",
+ "resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-2.1.2.tgz",
+ "integrity": "sha512-Btj2BOOO83o3WyH59e8MgXsxEQVcarkUOpEYrubB0urwnN10yQ364rsiByU11nZlqWYZm05i/of7io4mzihBtQ==",
+ "devOptional": true,
+ "license": "Apache-2.0",
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/doctrine": {
+ "version": "2.1.0",
+ "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-2.1.0.tgz",
+ "integrity": "sha512-35mSku4ZXK0vfCuHEDAwt55dg2jNajHZ1odvF+8SSr82EsZY4QmXfuWso8oEd8zRhVObSN18aM0CjSdoBX7zIw==",
+ "dev": true,
+ "license": "Apache-2.0",
+ "dependencies": {
+ "esutils": "^2.0.2"
+ },
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/drizzle-kit": {
+ "version": "0.31.10",
+ "resolved": "https://registry.npmjs.org/drizzle-kit/-/drizzle-kit-0.31.10.tgz",
+ "integrity": "sha512-7OZcmQUrdGI+DUNNsKBn1aW8qSoKuTH7d0mYgSP8bAzdFzKoovxEFnoGQp2dVs82EOJeYycqRtciopszwUf8bw==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@drizzle-team/brocli": "^0.10.2",
+ "@esbuild-kit/esm-loader": "^2.5.5",
+ "esbuild": "^0.25.4",
+ "tsx": "^4.21.0"
+ },
+ "bin": {
+ "drizzle-kit": "bin.cjs"
+ }
+ },
+ "node_modules/drizzle-kit/node_modules/@esbuild/aix-ppc64": {
+ "version": "0.25.12",
+ "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.25.12.tgz",
+ "integrity": "sha512-Hhmwd6CInZ3dwpuGTF8fJG6yoWmsToE+vYgD4nytZVxcu1ulHpUQRAB1UJ8+N1Am3Mz4+xOByoQoSZf4D+CpkA==",
+ "cpu": [
+ "ppc64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "aix"
+ ],
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/drizzle-kit/node_modules/@esbuild/android-arm": {
+ "version": "0.25.12",
+ "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.25.12.tgz",
+ "integrity": "sha512-VJ+sKvNA/GE7Ccacc9Cha7bpS8nyzVv0jdVgwNDaR4gDMC/2TTRc33Ip8qrNYUcpkOHUT5OZ0bUcNNVZQ9RLlg==",
+ "cpu": [
+ "arm"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "android"
+ ],
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/drizzle-kit/node_modules/@esbuild/android-arm64": {
+ "version": "0.25.12",
+ "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.25.12.tgz",
+ "integrity": "sha512-6AAmLG7zwD1Z159jCKPvAxZd4y/VTO0VkprYy+3N2FtJ8+BQWFXU+OxARIwA46c5tdD9SsKGZ/1ocqBS/gAKHg==",
+ "cpu": [
+ "arm64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "android"
+ ],
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/drizzle-kit/node_modules/@esbuild/android-x64": {
+ "version": "0.25.12",
+ "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.25.12.tgz",
+ "integrity": "sha512-5jbb+2hhDHx5phYR2By8GTWEzn6I9UqR11Kwf22iKbNpYrsmRB18aX/9ivc5cabcUiAT/wM+YIZ6SG9QO6a8kg==",
+ "cpu": [
+ "x64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "android"
+ ],
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/drizzle-kit/node_modules/@esbuild/darwin-arm64": {
+ "version": "0.25.12",
+ "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.25.12.tgz",
+ "integrity": "sha512-N3zl+lxHCifgIlcMUP5016ESkeQjLj/959RxxNYIthIg+CQHInujFuXeWbWMgnTo4cp5XVHqFPmpyu9J65C1Yg==",
+ "cpu": [
+ "arm64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "darwin"
+ ],
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/drizzle-kit/node_modules/@esbuild/darwin-x64": {
+ "version": "0.25.12",
+ "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.25.12.tgz",
+ "integrity": "sha512-HQ9ka4Kx21qHXwtlTUVbKJOAnmG1ipXhdWTmNXiPzPfWKpXqASVcWdnf2bnL73wgjNrFXAa3yYvBSd9pzfEIpA==",
+ "cpu": [
+ "x64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "darwin"
+ ],
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/drizzle-kit/node_modules/@esbuild/freebsd-arm64": {
+ "version": "0.25.12",
+ "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.25.12.tgz",
+ "integrity": "sha512-gA0Bx759+7Jve03K1S0vkOu5Lg/85dou3EseOGUes8flVOGxbhDDh/iZaoek11Y8mtyKPGF3vP8XhnkDEAmzeg==",
+ "cpu": [
+ "arm64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "freebsd"
+ ],
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/drizzle-kit/node_modules/@esbuild/freebsd-x64": {
+ "version": "0.25.12",
+ "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.25.12.tgz",
+ "integrity": "sha512-TGbO26Yw2xsHzxtbVFGEXBFH0FRAP7gtcPE7P5yP7wGy7cXK2oO7RyOhL5NLiqTlBh47XhmIUXuGciXEqYFfBQ==",
+ "cpu": [
+ "x64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "freebsd"
+ ],
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/drizzle-kit/node_modules/@esbuild/linux-arm": {
+ "version": "0.25.12",
+ "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.25.12.tgz",
+ "integrity": "sha512-lPDGyC1JPDou8kGcywY0YILzWlhhnRjdof3UlcoqYmS9El818LLfJJc3PXXgZHrHCAKs/Z2SeZtDJr5MrkxtOw==",
+ "cpu": [
+ "arm"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/drizzle-kit/node_modules/@esbuild/linux-arm64": {
+ "version": "0.25.12",
+ "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.25.12.tgz",
+ "integrity": "sha512-8bwX7a8FghIgrupcxb4aUmYDLp8pX06rGh5HqDT7bB+8Rdells6mHvrFHHW2JAOPZUbnjUpKTLg6ECyzvas2AQ==",
+ "cpu": [
+ "arm64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/drizzle-kit/node_modules/@esbuild/linux-ia32": {
+ "version": "0.25.12",
+ "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.25.12.tgz",
+ "integrity": "sha512-0y9KrdVnbMM2/vG8KfU0byhUN+EFCny9+8g202gYqSSVMonbsCfLjUO+rCci7pM0WBEtz+oK/PIwHkzxkyharA==",
+ "cpu": [
+ "ia32"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/drizzle-kit/node_modules/@esbuild/linux-loong64": {
+ "version": "0.25.12",
+ "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.25.12.tgz",
+ "integrity": "sha512-h///Lr5a9rib/v1GGqXVGzjL4TMvVTv+s1DPoxQdz7l/AYv6LDSxdIwzxkrPW438oUXiDtwM10o9PmwS/6Z0Ng==",
+ "cpu": [
+ "loong64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/drizzle-kit/node_modules/@esbuild/linux-mips64el": {
+ "version": "0.25.12",
+ "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.25.12.tgz",
+ "integrity": "sha512-iyRrM1Pzy9GFMDLsXn1iHUm18nhKnNMWscjmp4+hpafcZjrr2WbT//d20xaGljXDBYHqRcl8HnxbX6uaA/eGVw==",
+ "cpu": [
+ "mips64el"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/drizzle-kit/node_modules/@esbuild/linux-ppc64": {
+ "version": "0.25.12",
+ "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.25.12.tgz",
+ "integrity": "sha512-9meM/lRXxMi5PSUqEXRCtVjEZBGwB7P/D4yT8UG/mwIdze2aV4Vo6U5gD3+RsoHXKkHCfSxZKzmDssVlRj1QQA==",
+ "cpu": [
+ "ppc64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/drizzle-kit/node_modules/@esbuild/linux-riscv64": {
+ "version": "0.25.12",
+ "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.25.12.tgz",
+ "integrity": "sha512-Zr7KR4hgKUpWAwb1f3o5ygT04MzqVrGEGXGLnj15YQDJErYu/BGg+wmFlIDOdJp0PmB0lLvxFIOXZgFRrdjR0w==",
+ "cpu": [
+ "riscv64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/drizzle-kit/node_modules/@esbuild/linux-s390x": {
+ "version": "0.25.12",
+ "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.25.12.tgz",
+ "integrity": "sha512-MsKncOcgTNvdtiISc/jZs/Zf8d0cl/t3gYWX8J9ubBnVOwlk65UIEEvgBORTiljloIWnBzLs4qhzPkJcitIzIg==",
+ "cpu": [
+ "s390x"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/drizzle-kit/node_modules/@esbuild/linux-x64": {
+ "version": "0.25.12",
+ "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.25.12.tgz",
+ "integrity": "sha512-uqZMTLr/zR/ed4jIGnwSLkaHmPjOjJvnm6TVVitAa08SLS9Z0VM8wIRx7gWbJB5/J54YuIMInDquWyYvQLZkgw==",
+ "cpu": [
+ "x64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/drizzle-kit/node_modules/@esbuild/netbsd-arm64": {
+ "version": "0.25.12",
+ "resolved": "https://registry.npmjs.org/@esbuild/netbsd-arm64/-/netbsd-arm64-0.25.12.tgz",
+ "integrity": "sha512-xXwcTq4GhRM7J9A8Gv5boanHhRa/Q9KLVmcyXHCTaM4wKfIpWkdXiMog/KsnxzJ0A1+nD+zoecuzqPmCRyBGjg==",
+ "cpu": [
+ "arm64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "netbsd"
+ ],
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/drizzle-kit/node_modules/@esbuild/netbsd-x64": {
+ "version": "0.25.12",
+ "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.25.12.tgz",
+ "integrity": "sha512-Ld5pTlzPy3YwGec4OuHh1aCVCRvOXdH8DgRjfDy/oumVovmuSzWfnSJg+VtakB9Cm0gxNO9BzWkj6mtO1FMXkQ==",
+ "cpu": [
+ "x64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "netbsd"
+ ],
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/drizzle-kit/node_modules/@esbuild/openbsd-arm64": {
+ "version": "0.25.12",
+ "resolved": "https://registry.npmjs.org/@esbuild/openbsd-arm64/-/openbsd-arm64-0.25.12.tgz",
+ "integrity": "sha512-fF96T6KsBo/pkQI950FARU9apGNTSlZGsv1jZBAlcLL1MLjLNIWPBkj5NlSz8aAzYKg+eNqknrUJ24QBybeR5A==",
+ "cpu": [
+ "arm64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "openbsd"
+ ],
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/drizzle-kit/node_modules/@esbuild/openbsd-x64": {
+ "version": "0.25.12",
+ "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.25.12.tgz",
+ "integrity": "sha512-MZyXUkZHjQxUvzK7rN8DJ3SRmrVrke8ZyRusHlP+kuwqTcfWLyqMOE3sScPPyeIXN/mDJIfGXvcMqCgYKekoQw==",
+ "cpu": [
+ "x64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "openbsd"
+ ],
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/drizzle-kit/node_modules/@esbuild/openharmony-arm64": {
+ "version": "0.25.12",
+ "resolved": "https://registry.npmjs.org/@esbuild/openharmony-arm64/-/openharmony-arm64-0.25.12.tgz",
+ "integrity": "sha512-rm0YWsqUSRrjncSXGA7Zv78Nbnw4XL6/dzr20cyrQf7ZmRcsovpcRBdhD43Nuk3y7XIoW2OxMVvwuRvk9XdASg==",
+ "cpu": [
+ "arm64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "openharmony"
+ ],
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/drizzle-kit/node_modules/@esbuild/sunos-x64": {
+ "version": "0.25.12",
+ "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.25.12.tgz",
+ "integrity": "sha512-3wGSCDyuTHQUzt0nV7bocDy72r2lI33QL3gkDNGkod22EsYl04sMf0qLb8luNKTOmgF/eDEDP5BFNwoBKH441w==",
+ "cpu": [
+ "x64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "sunos"
+ ],
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/drizzle-kit/node_modules/@esbuild/win32-arm64": {
+ "version": "0.25.12",
+ "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.25.12.tgz",
+ "integrity": "sha512-rMmLrur64A7+DKlnSuwqUdRKyd3UE7oPJZmnljqEptesKM8wx9J8gx5u0+9Pq0fQQW8vqeKebwNXdfOyP+8Bsg==",
+ "cpu": [
+ "arm64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "win32"
+ ],
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/drizzle-kit/node_modules/@esbuild/win32-ia32": {
+ "version": "0.25.12",
+ "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.25.12.tgz",
+ "integrity": "sha512-HkqnmmBoCbCwxUKKNPBixiWDGCpQGVsrQfJoVGYLPT41XWF8lHuE5N6WhVia2n4o5QK5M4tYr21827fNhi4byQ==",
+ "cpu": [
+ "ia32"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "win32"
+ ],
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/drizzle-kit/node_modules/@esbuild/win32-x64": {
+ "version": "0.25.12",
+ "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.25.12.tgz",
+ "integrity": "sha512-alJC0uCZpTFrSL0CCDjcgleBXPnCrEAhTBILpeAp7M/OFgoqtAetfBzX0xM00MUsVVPpVjlPuMbREqnZCXaTnA==",
+ "cpu": [
+ "x64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "win32"
+ ],
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/drizzle-kit/node_modules/esbuild": {
+ "version": "0.25.12",
+ "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.25.12.tgz",
+ "integrity": "sha512-bbPBYYrtZbkt6Os6FiTLCTFxvq4tt3JKall1vRwshA3fdVztsLAatFaZobhkBC8/BrPetoa0oksYoKXoG4ryJg==",
+ "dev": true,
+ "hasInstallScript": true,
+ "license": "MIT",
+ "bin": {
+ "esbuild": "bin/esbuild"
+ },
+ "engines": {
+ "node": ">=18"
+ },
+ "optionalDependencies": {
+ "@esbuild/aix-ppc64": "0.25.12",
+ "@esbuild/android-arm": "0.25.12",
+ "@esbuild/android-arm64": "0.25.12",
+ "@esbuild/android-x64": "0.25.12",
+ "@esbuild/darwin-arm64": "0.25.12",
+ "@esbuild/darwin-x64": "0.25.12",
+ "@esbuild/freebsd-arm64": "0.25.12",
+ "@esbuild/freebsd-x64": "0.25.12",
+ "@esbuild/linux-arm": "0.25.12",
+ "@esbuild/linux-arm64": "0.25.12",
+ "@esbuild/linux-ia32": "0.25.12",
+ "@esbuild/linux-loong64": "0.25.12",
+ "@esbuild/linux-mips64el": "0.25.12",
+ "@esbuild/linux-ppc64": "0.25.12",
+ "@esbuild/linux-riscv64": "0.25.12",
+ "@esbuild/linux-s390x": "0.25.12",
+ "@esbuild/linux-x64": "0.25.12",
+ "@esbuild/netbsd-arm64": "0.25.12",
+ "@esbuild/netbsd-x64": "0.25.12",
+ "@esbuild/openbsd-arm64": "0.25.12",
+ "@esbuild/openbsd-x64": "0.25.12",
+ "@esbuild/openharmony-arm64": "0.25.12",
+ "@esbuild/sunos-x64": "0.25.12",
+ "@esbuild/win32-arm64": "0.25.12",
+ "@esbuild/win32-ia32": "0.25.12",
+ "@esbuild/win32-x64": "0.25.12"
+ }
+ },
+ "node_modules/drizzle-orm": {
+ "version": "0.45.2",
+ "resolved": "https://registry.npmjs.org/drizzle-orm/-/drizzle-orm-0.45.2.tgz",
+ "integrity": "sha512-kY0BSaTNYWnoDMVoyY8uxmyHjpJW1geOmBMdSSicKo9CIIWkSxMIj2rkeSR51b8KAPB7m+qysjuHme5nKP+E5Q==",
+ "license": "Apache-2.0",
+ "peerDependencies": {
+ "@aws-sdk/client-rds-data": ">=3",
+ "@cloudflare/workers-types": ">=4",
+ "@electric-sql/pglite": ">=0.2.0",
+ "@libsql/client": ">=0.10.0",
+ "@libsql/client-wasm": ">=0.10.0",
+ "@neondatabase/serverless": ">=0.10.0",
+ "@op-engineering/op-sqlite": ">=2",
+ "@opentelemetry/api": "^1.4.1",
+ "@planetscale/database": ">=1.13",
+ "@prisma/client": "*",
+ "@tidbcloud/serverless": "*",
+ "@types/better-sqlite3": "*",
+ "@types/pg": "*",
+ "@types/sql.js": "*",
+ "@upstash/redis": ">=1.34.7",
+ "@vercel/postgres": ">=0.8.0",
+ "@xata.io/client": "*",
+ "better-sqlite3": ">=7",
+ "bun-types": "*",
+ "expo-sqlite": ">=14.0.0",
+ "gel": ">=2",
+ "knex": "*",
+ "kysely": "*",
+ "mysql2": ">=2",
+ "pg": ">=8",
+ "postgres": ">=3",
+ "sql.js": ">=1",
+ "sqlite3": ">=5"
+ },
+ "peerDependenciesMeta": {
+ "@aws-sdk/client-rds-data": {
+ "optional": true
+ },
+ "@cloudflare/workers-types": {
+ "optional": true
+ },
+ "@electric-sql/pglite": {
+ "optional": true
+ },
+ "@libsql/client": {
+ "optional": true
+ },
+ "@libsql/client-wasm": {
+ "optional": true
+ },
+ "@neondatabase/serverless": {
+ "optional": true
+ },
+ "@op-engineering/op-sqlite": {
+ "optional": true
+ },
+ "@opentelemetry/api": {
+ "optional": true
+ },
+ "@planetscale/database": {
+ "optional": true
+ },
+ "@prisma/client": {
+ "optional": true
+ },
+ "@tidbcloud/serverless": {
+ "optional": true
+ },
+ "@types/better-sqlite3": {
+ "optional": true
+ },
+ "@types/pg": {
+ "optional": true
+ },
+ "@types/sql.js": {
+ "optional": true
+ },
+ "@upstash/redis": {
+ "optional": true
+ },
+ "@vercel/postgres": {
+ "optional": true
+ },
+ "@xata.io/client": {
+ "optional": true
+ },
+ "better-sqlite3": {
+ "optional": true
+ },
+ "bun-types": {
+ "optional": true
+ },
+ "expo-sqlite": {
+ "optional": true
+ },
+ "gel": {
+ "optional": true
+ },
+ "knex": {
+ "optional": true
+ },
+ "kysely": {
+ "optional": true
+ },
+ "mysql2": {
+ "optional": true
+ },
+ "pg": {
+ "optional": true
+ },
+ "postgres": {
+ "optional": true
+ },
+ "prisma": {
+ "optional": true
+ },
+ "sql.js": {
+ "optional": true
+ },
+ "sqlite3": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/dunder-proto": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/dunder-proto/-/dunder-proto-1.0.1.tgz",
+ "integrity": "sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "call-bind-apply-helpers": "^1.0.1",
+ "es-errors": "^1.3.0",
+ "gopd": "^1.2.0"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ }
+ },
+ "node_modules/electron-to-chromium": {
+ "version": "1.5.358",
+ "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.358.tgz",
+ "integrity": "sha512-EO7tKm3QxRqTs1lSuPXzl6yRAwznehp0AH9OoMOIC+4mQzTFday8FJCO5KU6J/TFSQXEOahNq4vTKpz1jmCVOA==",
+ "dev": true,
+ "license": "ISC"
+ },
+ "node_modules/emoji-regex": {
+ "version": "9.2.2",
+ "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-9.2.2.tgz",
+ "integrity": "sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/emoji-regex-xs": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/emoji-regex-xs/-/emoji-regex-xs-2.0.1.tgz",
+ "integrity": "sha512-1QFuh8l7LqUcKe24LsPUNzjrzJQ7pgRwp1QMcZ5MX6mFplk2zQ08NVCM84++1cveaUUYtcCYHmeFEuNg16sU4g==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=10.0.0"
+ }
+ },
+ "node_modules/enhanced-resolve": {
+ "version": "5.21.3",
+ "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.21.3.tgz",
+ "integrity": "sha512-QyL119InA+XXEkNLNTPCXPugSvOfhwv0JOlGNzvxs0hZaiHLNvXSpudUWsOlsXGWJh8G6ckCScEkVHfX3kw/2Q==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "graceful-fs": "^4.2.4",
+ "tapable": "^2.3.3"
+ },
+ "engines": {
+ "node": ">=10.13.0"
+ }
+ },
+ "node_modules/error-stack-parser-es": {
+ "version": "1.0.5",
+ "resolved": "https://registry.npmjs.org/error-stack-parser-es/-/error-stack-parser-es-1.0.5.tgz",
+ "integrity": "sha512-5qucVt2XcuGMcEGgWI7i+yZpmpByQ8J1lHhcL7PwqCwu9FPP3VUXzT4ltHe5i2z9dePwEHcDVOAfSnHsOlCXRA==",
+ "dev": true,
+ "license": "MIT",
+ "funding": {
+ "url": "https://github.com/sponsors/antfu"
+ }
+ },
+ "node_modules/es-abstract": {
+ "version": "1.24.2",
+ "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.24.2.tgz",
+ "integrity": "sha512-2FpH9Q5i2RRwyEP1AylXe6nYLR5OhaJTZwmlcP0dL/+JCbgg7yyEo/sEK6HeGZRf3dFpWwThaRHVApXSkW3xeg==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "array-buffer-byte-length": "^1.0.2",
+ "arraybuffer.prototype.slice": "^1.0.4",
+ "available-typed-arrays": "^1.0.7",
+ "call-bind": "^1.0.8",
+ "call-bound": "^1.0.4",
+ "data-view-buffer": "^1.0.2",
+ "data-view-byte-length": "^1.0.2",
+ "data-view-byte-offset": "^1.0.1",
+ "es-define-property": "^1.0.1",
+ "es-errors": "^1.3.0",
+ "es-object-atoms": "^1.1.1",
+ "es-set-tostringtag": "^2.1.0",
+ "es-to-primitive": "^1.3.0",
+ "function.prototype.name": "^1.1.8",
+ "get-intrinsic": "^1.3.0",
+ "get-proto": "^1.0.1",
+ "get-symbol-description": "^1.1.0",
+ "globalthis": "^1.0.4",
+ "gopd": "^1.2.0",
+ "has-property-descriptors": "^1.0.2",
+ "has-proto": "^1.2.0",
+ "has-symbols": "^1.1.0",
+ "hasown": "^2.0.2",
+ "internal-slot": "^1.1.0",
+ "is-array-buffer": "^3.0.5",
+ "is-callable": "^1.2.7",
+ "is-data-view": "^1.0.2",
+ "is-negative-zero": "^2.0.3",
+ "is-regex": "^1.2.1",
+ "is-set": "^2.0.3",
+ "is-shared-array-buffer": "^1.0.4",
+ "is-string": "^1.1.1",
+ "is-typed-array": "^1.1.15",
+ "is-weakref": "^1.1.1",
+ "math-intrinsics": "^1.1.0",
+ "object-inspect": "^1.13.4",
+ "object-keys": "^1.1.1",
+ "object.assign": "^4.1.7",
+ "own-keys": "^1.0.1",
+ "regexp.prototype.flags": "^1.5.4",
+ "safe-array-concat": "^1.1.3",
+ "safe-push-apply": "^1.0.0",
+ "safe-regex-test": "^1.1.0",
+ "set-proto": "^1.0.0",
+ "stop-iteration-iterator": "^1.1.0",
+ "string.prototype.trim": "^1.2.10",
+ "string.prototype.trimend": "^1.0.9",
+ "string.prototype.trimstart": "^1.0.8",
+ "typed-array-buffer": "^1.0.3",
+ "typed-array-byte-length": "^1.0.3",
+ "typed-array-byte-offset": "^1.0.4",
+ "typed-array-length": "^1.0.7",
+ "unbox-primitive": "^1.1.0",
+ "which-typed-array": "^1.1.19"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/es-define-property": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/es-define-property/-/es-define-property-1.0.1.tgz",
+ "integrity": "sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">= 0.4"
+ }
+ },
+ "node_modules/es-errors": {
+ "version": "1.3.0",
+ "resolved": "https://registry.npmjs.org/es-errors/-/es-errors-1.3.0.tgz",
+ "integrity": "sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">= 0.4"
+ }
+ },
+ "node_modules/es-iterator-helpers": {
+ "version": "1.3.2",
+ "resolved": "https://registry.npmjs.org/es-iterator-helpers/-/es-iterator-helpers-1.3.2.tgz",
+ "integrity": "sha512-HVLACW1TppGYjJ8H6/jqH/pqOtKRw6wMlrB23xfExmFWxFquAIWCmwoLsOyN96K4a5KbmOf5At9ZUO3GZbetAw==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "call-bind": "^1.0.9",
+ "call-bound": "^1.0.4",
+ "define-properties": "^1.2.1",
+ "es-abstract": "^1.24.2",
+ "es-errors": "^1.3.0",
+ "es-set-tostringtag": "^2.1.0",
+ "function-bind": "^1.1.2",
+ "get-intrinsic": "^1.3.0",
+ "globalthis": "^1.0.4",
+ "gopd": "^1.2.0",
+ "has-property-descriptors": "^1.0.2",
+ "has-proto": "^1.2.0",
+ "has-symbols": "^1.1.0",
+ "internal-slot": "^1.1.0",
+ "iterator.prototype": "^1.1.5",
+ "math-intrinsics": "^1.1.0"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ }
+ },
+ "node_modules/es-module-lexer": {
+ "version": "2.1.0",
+ "resolved": "https://registry.npmjs.org/es-module-lexer/-/es-module-lexer-2.1.0.tgz",
+ "integrity": "sha512-n27zTYMjYu1aj4MjCWzSP7G9r75utsaoc8m61weK+W8JMBGGQybd43GstCXZ3WNmSFtGT9wi59qQTW6mhTR5LQ==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/es-object-atoms": {
+ "version": "1.1.1",
+ "resolved": "https://registry.npmjs.org/es-object-atoms/-/es-object-atoms-1.1.1.tgz",
+ "integrity": "sha512-FGgH2h8zKNim9ljj7dankFPcICIK9Cp5bm+c2gQSYePhpaG5+esrLODihIorn+Pe6FGJzWhXQotPv73jTaldXA==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "es-errors": "^1.3.0"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ }
+ },
+ "node_modules/es-set-tostringtag": {
+ "version": "2.1.0",
+ "resolved": "https://registry.npmjs.org/es-set-tostringtag/-/es-set-tostringtag-2.1.0.tgz",
+ "integrity": "sha512-j6vWzfrGVfyXxge+O0x5sh6cvxAog0a/4Rdd2K36zCMV5eJ+/+tOAngRO8cODMNWbVRdVlmGZQL2YS3yR8bIUA==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "es-errors": "^1.3.0",
+ "get-intrinsic": "^1.2.6",
+ "has-tostringtag": "^1.0.2",
+ "hasown": "^2.0.2"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ }
+ },
+ "node_modules/es-shim-unscopables": {
+ "version": "1.1.0",
+ "resolved": "https://registry.npmjs.org/es-shim-unscopables/-/es-shim-unscopables-1.1.0.tgz",
+ "integrity": "sha512-d9T8ucsEhh8Bi1woXCf+TIKDIROLG5WCkxg8geBCbvk22kzwC5G2OnXVMO6FUsvQlgUUXQ2itephWDLqDzbeCw==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "hasown": "^2.0.2"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ }
+ },
+ "node_modules/es-to-primitive": {
+ "version": "1.3.0",
+ "resolved": "https://registry.npmjs.org/es-to-primitive/-/es-to-primitive-1.3.0.tgz",
+ "integrity": "sha512-w+5mJ3GuFL+NjVtJlvydShqE1eN3h3PbI7/5LAsYJP/2qtuMXjfL2LpHSRqo4b4eSF5K/DH1JXKUAHSB2UW50g==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "is-callable": "^1.2.7",
+ "is-date-object": "^1.0.5",
+ "is-symbol": "^1.0.4"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/esbuild": {
+ "version": "0.28.0",
+ "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.28.0.tgz",
+ "integrity": "sha512-sNR9MHpXSUV/XB4zmsFKN+QgVG82Cc7+/aaxJ8Adi8hyOac+EXptIp45QBPaVyX3N70664wRbTcLTOemCAnyqw==",
+ "dev": true,
+ "hasInstallScript": true,
+ "license": "MIT",
+ "bin": {
+ "esbuild": "bin/esbuild"
+ },
+ "engines": {
+ "node": ">=18"
+ },
+ "optionalDependencies": {
+ "@esbuild/aix-ppc64": "0.28.0",
+ "@esbuild/android-arm": "0.28.0",
+ "@esbuild/android-arm64": "0.28.0",
+ "@esbuild/android-x64": "0.28.0",
+ "@esbuild/darwin-arm64": "0.28.0",
+ "@esbuild/darwin-x64": "0.28.0",
+ "@esbuild/freebsd-arm64": "0.28.0",
+ "@esbuild/freebsd-x64": "0.28.0",
+ "@esbuild/linux-arm": "0.28.0",
+ "@esbuild/linux-arm64": "0.28.0",
+ "@esbuild/linux-ia32": "0.28.0",
+ "@esbuild/linux-loong64": "0.28.0",
+ "@esbuild/linux-mips64el": "0.28.0",
+ "@esbuild/linux-ppc64": "0.28.0",
+ "@esbuild/linux-riscv64": "0.28.0",
+ "@esbuild/linux-s390x": "0.28.0",
+ "@esbuild/linux-x64": "0.28.0",
+ "@esbuild/netbsd-arm64": "0.28.0",
+ "@esbuild/netbsd-x64": "0.28.0",
+ "@esbuild/openbsd-arm64": "0.28.0",
+ "@esbuild/openbsd-x64": "0.28.0",
+ "@esbuild/openharmony-arm64": "0.28.0",
+ "@esbuild/sunos-x64": "0.28.0",
+ "@esbuild/win32-arm64": "0.28.0",
+ "@esbuild/win32-ia32": "0.28.0",
+ "@esbuild/win32-x64": "0.28.0"
+ }
+ },
+ "node_modules/escalade": {
+ "version": "3.2.0",
+ "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.2.0.tgz",
+ "integrity": "sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=6"
+ }
+ },
+ "node_modules/escape-html": {
+ "version": "1.0.3",
+ "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz",
+ "integrity": "sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/escape-string-regexp": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz",
+ "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=10"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/eslint": {
+ "version": "9.39.4",
+ "resolved": "https://registry.npmjs.org/eslint/-/eslint-9.39.4.tgz",
+ "integrity": "sha512-XoMjdBOwe/esVgEvLmNsD3IRHkm7fbKIUGvrleloJXUZgDHig2IPWNniv+GwjyJXzuNqVjlr5+4yVUZjycJwfQ==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@eslint-community/eslint-utils": "^4.8.0",
+ "@eslint-community/regexpp": "^4.12.1",
+ "@eslint/config-array": "^0.21.2",
+ "@eslint/config-helpers": "^0.4.2",
+ "@eslint/core": "^0.17.0",
+ "@eslint/eslintrc": "^3.3.5",
+ "@eslint/js": "9.39.4",
+ "@eslint/plugin-kit": "^0.4.1",
+ "@humanfs/node": "^0.16.6",
+ "@humanwhocodes/module-importer": "^1.0.1",
+ "@humanwhocodes/retry": "^0.4.2",
+ "@types/estree": "^1.0.6",
+ "ajv": "^6.14.0",
+ "chalk": "^4.0.0",
+ "cross-spawn": "^7.0.6",
+ "debug": "^4.3.2",
+ "escape-string-regexp": "^4.0.0",
+ "eslint-scope": "^8.4.0",
+ "eslint-visitor-keys": "^4.2.1",
+ "espree": "^10.4.0",
+ "esquery": "^1.5.0",
+ "esutils": "^2.0.2",
+ "fast-deep-equal": "^3.1.3",
+ "file-entry-cache": "^8.0.0",
+ "find-up": "^5.0.0",
+ "glob-parent": "^6.0.2",
+ "ignore": "^5.2.0",
+ "imurmurhash": "^0.1.4",
+ "is-glob": "^4.0.0",
+ "json-stable-stringify-without-jsonify": "^1.0.1",
+ "lodash.merge": "^4.6.2",
+ "minimatch": "^3.1.5",
+ "natural-compare": "^1.4.0",
+ "optionator": "^0.9.3"
+ },
+ "bin": {
+ "eslint": "bin/eslint.js"
+ },
+ "engines": {
+ "node": "^18.18.0 || ^20.9.0 || >=21.1.0"
+ },
+ "funding": {
+ "url": "https://eslint.org/donate"
+ },
+ "peerDependencies": {
+ "jiti": "*"
+ },
+ "peerDependenciesMeta": {
+ "jiti": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/eslint-config-next": {
+ "version": "16.2.12",
+ "resolved": "https://registry.npmjs.org/eslint-config-next/-/eslint-config-next-16.2.12.tgz",
+ "integrity": "sha512-iaaf4vvKo5h2LBdGt0JuRv7t0Ysqr9FMCiFxbptDg8LqOE//mIKR80DdpOnSVM7qjLH3jT8P0aFiwXxBEGZRXw==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@next/eslint-plugin-next": "16.2.12",
+ "eslint-import-resolver-node": "^0.3.6",
+ "eslint-import-resolver-typescript": "^3.5.2",
+ "eslint-plugin-import": "^2.32.0",
+ "eslint-plugin-jsx-a11y": "^6.10.0",
+ "eslint-plugin-react": "^7.37.0",
+ "eslint-plugin-react-hooks": "^7.0.0",
+ "globals": "16.4.0",
+ "typescript-eslint": "^8.46.0"
+ },
+ "peerDependencies": {
+ "eslint": ">=9.0.0",
+ "typescript": ">=3.3.1"
+ },
+ "peerDependenciesMeta": {
+ "typescript": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/eslint-config-next/node_modules/globals": {
+ "version": "16.4.0",
+ "resolved": "https://registry.npmjs.org/globals/-/globals-16.4.0.tgz",
+ "integrity": "sha512-ob/2LcVVaVGCYN+r14cnwnoDPUufjiYgSqRhiFD0Q1iI4Odora5RE8Iv1D24hAz5oMophRGkGz+yuvQmmUMnMw==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=18"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/eslint-import-resolver-node": {
+ "version": "0.3.10",
+ "resolved": "https://registry.npmjs.org/eslint-import-resolver-node/-/eslint-import-resolver-node-0.3.10.tgz",
+ "integrity": "sha512-tRrKqFyCaKict5hOd244sL6EQFNycnMQnBe+j8uqGNXYzsImGbGUU4ibtoaBmv5FLwJwcFJNeg1GeVjQfbMrDQ==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "debug": "^3.2.7",
+ "is-core-module": "^2.16.1",
+ "resolve": "^2.0.0-next.6"
+ }
+ },
+ "node_modules/eslint-import-resolver-node/node_modules/debug": {
+ "version": "3.2.7",
+ "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz",
+ "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "ms": "^2.1.1"
+ }
+ },
+ "node_modules/eslint-import-resolver-typescript": {
+ "version": "3.10.1",
+ "resolved": "https://registry.npmjs.org/eslint-import-resolver-typescript/-/eslint-import-resolver-typescript-3.10.1.tgz",
+ "integrity": "sha512-A1rHYb06zjMGAxdLSkN2fXPBwuSaQ0iO5M/hdyS0Ajj1VBaRp0sPD3dn1FhME3c/JluGFbwSxyCfqdSbtQLAHQ==",
+ "dev": true,
+ "license": "ISC",
+ "dependencies": {
+ "@nolyfill/is-core-module": "1.0.39",
+ "debug": "^4.4.0",
+ "get-tsconfig": "^4.10.0",
+ "is-bun-module": "^2.0.0",
+ "stable-hash": "^0.0.5",
+ "tinyglobby": "^0.2.13",
+ "unrs-resolver": "^1.6.2"
+ },
+ "engines": {
+ "node": "^14.18.0 || >=16.0.0"
+ },
+ "funding": {
+ "url": "https://opencollective.com/eslint-import-resolver-typescript"
+ },
+ "peerDependencies": {
+ "eslint": "*",
+ "eslint-plugin-import": "*",
+ "eslint-plugin-import-x": "*"
+ },
+ "peerDependenciesMeta": {
+ "eslint-plugin-import": {
+ "optional": true
+ },
+ "eslint-plugin-import-x": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/eslint-module-utils": {
+ "version": "2.12.1",
+ "resolved": "https://registry.npmjs.org/eslint-module-utils/-/eslint-module-utils-2.12.1.tgz",
+ "integrity": "sha512-L8jSWTze7K2mTg0vos/RuLRS5soomksDPoJLXIslC7c8Wmut3bx7CPpJijDcBZtxQ5lrbUdM+s0OlNbz0DCDNw==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "debug": "^3.2.7"
+ },
+ "engines": {
+ "node": ">=4"
+ },
+ "peerDependenciesMeta": {
+ "eslint": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/eslint-module-utils/node_modules/debug": {
+ "version": "3.2.7",
+ "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz",
+ "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "ms": "^2.1.1"
+ }
+ },
+ "node_modules/eslint-plugin-import": {
+ "version": "2.32.0",
+ "resolved": "https://registry.npmjs.org/eslint-plugin-import/-/eslint-plugin-import-2.32.0.tgz",
+ "integrity": "sha512-whOE1HFo/qJDyX4SnXzP4N6zOWn79WhnCUY/iDR0mPfQZO8wcYE4JClzI2oZrhBnnMUCBCHZhO6VQyoBU95mZA==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@rtsao/scc": "^1.1.0",
+ "array-includes": "^3.1.9",
+ "array.prototype.findlastindex": "^1.2.6",
+ "array.prototype.flat": "^1.3.3",
+ "array.prototype.flatmap": "^1.3.3",
+ "debug": "^3.2.7",
+ "doctrine": "^2.1.0",
+ "eslint-import-resolver-node": "^0.3.9",
+ "eslint-module-utils": "^2.12.1",
+ "hasown": "^2.0.2",
+ "is-core-module": "^2.16.1",
+ "is-glob": "^4.0.3",
+ "minimatch": "^3.1.2",
+ "object.fromentries": "^2.0.8",
+ "object.groupby": "^1.0.3",
+ "object.values": "^1.2.1",
+ "semver": "^6.3.1",
+ "string.prototype.trimend": "^1.0.9",
+ "tsconfig-paths": "^3.15.0"
+ },
+ "engines": {
+ "node": ">=4"
+ },
+ "peerDependencies": {
+ "eslint": "^2 || ^3 || ^4 || ^5 || ^6 || ^7.2.0 || ^8 || ^9"
+ }
+ },
+ "node_modules/eslint-plugin-import/node_modules/debug": {
+ "version": "3.2.7",
+ "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz",
+ "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "ms": "^2.1.1"
+ }
+ },
+ "node_modules/eslint-plugin-jsx-a11y": {
+ "version": "6.10.2",
+ "resolved": "https://registry.npmjs.org/eslint-plugin-jsx-a11y/-/eslint-plugin-jsx-a11y-6.10.2.tgz",
+ "integrity": "sha512-scB3nz4WmG75pV8+3eRUQOHZlNSUhFNq37xnpgRkCCELU3XMvXAxLk1eqWWyE22Ki4Q01Fnsw9BA3cJHDPgn2Q==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "aria-query": "^5.3.2",
+ "array-includes": "^3.1.8",
+ "array.prototype.flatmap": "^1.3.2",
+ "ast-types-flow": "^0.0.8",
+ "axe-core": "^4.10.0",
+ "axobject-query": "^4.1.0",
+ "damerau-levenshtein": "^1.0.8",
+ "emoji-regex": "^9.2.2",
+ "hasown": "^2.0.2",
+ "jsx-ast-utils": "^3.3.5",
+ "language-tags": "^1.0.9",
+ "minimatch": "^3.1.2",
+ "object.fromentries": "^2.0.8",
+ "safe-regex-test": "^1.0.3",
+ "string.prototype.includes": "^2.0.1"
+ },
+ "engines": {
+ "node": ">=4.0"
+ },
+ "peerDependencies": {
+ "eslint": "^3 || ^4 || ^5 || ^6 || ^7 || ^8 || ^9"
+ }
+ },
+ "node_modules/eslint-plugin-react": {
+ "version": "7.37.5",
+ "resolved": "https://registry.npmjs.org/eslint-plugin-react/-/eslint-plugin-react-7.37.5.tgz",
+ "integrity": "sha512-Qteup0SqU15kdocexFNAJMvCJEfa2xUKNV4CC1xsVMrIIqEy3SQ/rqyxCWNzfrd3/ldy6HMlD2e0JDVpDg2qIA==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "array-includes": "^3.1.8",
+ "array.prototype.findlast": "^1.2.5",
+ "array.prototype.flatmap": "^1.3.3",
+ "array.prototype.tosorted": "^1.1.4",
+ "doctrine": "^2.1.0",
+ "es-iterator-helpers": "^1.2.1",
+ "estraverse": "^5.3.0",
+ "hasown": "^2.0.2",
+ "jsx-ast-utils": "^2.4.1 || ^3.0.0",
+ "minimatch": "^3.1.2",
+ "object.entries": "^1.1.9",
+ "object.fromentries": "^2.0.8",
+ "object.values": "^1.2.1",
+ "prop-types": "^15.8.1",
+ "resolve": "^2.0.0-next.5",
+ "semver": "^6.3.1",
+ "string.prototype.matchall": "^4.0.12",
+ "string.prototype.repeat": "^1.0.0"
+ },
+ "engines": {
+ "node": ">=4"
+ },
+ "peerDependencies": {
+ "eslint": "^3 || ^4 || ^5 || ^6 || ^7 || ^8 || ^9.7"
+ }
+ },
+ "node_modules/eslint-plugin-react-hooks": {
+ "version": "7.1.1",
+ "resolved": "https://registry.npmjs.org/eslint-plugin-react-hooks/-/eslint-plugin-react-hooks-7.1.1.tgz",
+ "integrity": "sha512-f2I7Gw6JbvCexzIInuSbZpfdQ44D7iqdWX01FKLvrPgqxoE7oMj8clOfto8U6vYiz4yd5oKu39rRSVOe1zRu0g==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@babel/core": "^7.24.4",
+ "@babel/parser": "^7.24.4",
+ "hermes-parser": "^0.25.1",
+ "zod": "^3.25.0 || ^4.0.0",
+ "zod-validation-error": "^3.5.0 || ^4.0.0"
+ },
+ "engines": {
+ "node": ">=18"
+ },
+ "peerDependencies": {
+ "eslint": "^3.0.0 || ^4.0.0 || ^5.0.0 || ^6.0.0 || ^7.0.0 || ^8.0.0-0 || ^9.0.0 || ^10.0.0"
+ }
+ },
+ "node_modules/eslint-scope": {
+ "version": "8.4.0",
+ "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-8.4.0.tgz",
+ "integrity": "sha512-sNXOfKCn74rt8RICKMvJS7XKV/Xk9kA7DyJr8mJik3S7Cwgy3qlkkmyS2uQB3jiJg6VNdZd/pDBJu0nvG2NlTg==",
+ "dev": true,
+ "license": "BSD-2-Clause",
+ "dependencies": {
+ "esrecurse": "^4.3.0",
+ "estraverse": "^5.2.0"
+ },
+ "engines": {
+ "node": "^18.18.0 || ^20.9.0 || >=21.1.0"
+ },
+ "funding": {
+ "url": "https://opencollective.com/eslint"
+ }
+ },
+ "node_modules/eslint-visitor-keys": {
+ "version": "4.2.1",
+ "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-4.2.1.tgz",
+ "integrity": "sha512-Uhdk5sfqcee/9H/rCOJikYz67o0a2Tw2hGRPOG2Y1R2dg7brRe1uG0yaNQDHu+TO/uQPF/5eCapvYSmHUjt7JQ==",
+ "dev": true,
+ "license": "Apache-2.0",
+ "engines": {
+ "node": "^18.18.0 || ^20.9.0 || >=21.1.0"
+ },
+ "funding": {
+ "url": "https://opencollective.com/eslint"
+ }
+ },
+ "node_modules/espree": {
+ "version": "10.4.0",
+ "resolved": "https://registry.npmjs.org/espree/-/espree-10.4.0.tgz",
+ "integrity": "sha512-j6PAQ2uUr79PZhBjP5C5fhl8e39FmRnOjsD5lGnWrFU8i2G776tBK7+nP8KuQUTTyAZUwfQqXAgrVH5MbH9CYQ==",
+ "dev": true,
+ "license": "BSD-2-Clause",
+ "dependencies": {
+ "acorn": "^8.15.0",
+ "acorn-jsx": "^5.3.2",
+ "eslint-visitor-keys": "^4.2.1"
+ },
+ "engines": {
+ "node": "^18.18.0 || ^20.9.0 || >=21.1.0"
+ },
+ "funding": {
+ "url": "https://opencollective.com/eslint"
+ }
+ },
+ "node_modules/esquery": {
+ "version": "1.7.0",
+ "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.7.0.tgz",
+ "integrity": "sha512-Ap6G0WQwcU/LHsvLwON1fAQX9Zp0A2Y6Y/cJBl9r/JbW90Zyg4/zbG6zzKa2OTALELarYHmKu0GhpM5EO+7T0g==",
+ "dev": true,
+ "license": "BSD-3-Clause",
+ "dependencies": {
+ "estraverse": "^5.1.0"
+ },
+ "engines": {
+ "node": ">=0.10"
+ }
+ },
+ "node_modules/esrecurse": {
+ "version": "4.3.0",
+ "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.3.0.tgz",
+ "integrity": "sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==",
+ "dev": true,
+ "license": "BSD-2-Clause",
+ "dependencies": {
+ "estraverse": "^5.2.0"
+ },
+ "engines": {
+ "node": ">=4.0"
+ }
+ },
+ "node_modules/estraverse": {
+ "version": "5.3.0",
+ "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz",
+ "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==",
+ "dev": true,
+ "license": "BSD-2-Clause",
+ "engines": {
+ "node": ">=4.0"
+ }
+ },
+ "node_modules/estree-walker": {
+ "version": "3.0.3",
+ "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-3.0.3.tgz",
+ "integrity": "sha512-7RUKfXgSMMkzt6ZuXmqapOurLGPPfgj6l9uRZ7lRGolvk0y2yocc35LdcxKC5PQZdn2DMqioAQ2NoWcrTKmm6g==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@types/estree": "^1.0.0"
+ }
+ },
+ "node_modules/esutils": {
+ "version": "2.0.3",
+ "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz",
+ "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==",
+ "dev": true,
+ "license": "BSD-2-Clause",
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/events": {
+ "version": "3.3.0",
+ "resolved": "https://registry.npmjs.org/events/-/events-3.3.0.tgz",
+ "integrity": "sha512-mQw+2fkQbALzQ7V0MY0IqdnXNOeTtP4r0lN9z7AAawCXgqea7bDii20AYrIBrFd/Hx0M2Ocz6S111CaFkUcb0Q==",
+ "dev": true,
+ "license": "MIT",
+ "peer": true,
+ "engines": {
+ "node": ">=0.8.x"
+ }
+ },
+ "node_modules/fast-deep-equal": {
+ "version": "3.1.3",
+ "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz",
+ "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/fast-glob": {
+ "version": "3.3.1",
+ "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.3.1.tgz",
+ "integrity": "sha512-kNFPyjhh5cKjrUltxs+wFx+ZkbRaxxmZ+X0ZU31SOsxCEtP9VPgtq2teZw1DebupL5GmDaNQ6yKMMVcM41iqDg==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@nodelib/fs.stat": "^2.0.2",
+ "@nodelib/fs.walk": "^1.2.3",
+ "glob-parent": "^5.1.2",
+ "merge2": "^1.3.0",
+ "micromatch": "^4.0.4"
+ },
+ "engines": {
+ "node": ">=8.6.0"
+ }
+ },
+ "node_modules/fast-glob/node_modules/glob-parent": {
+ "version": "5.1.2",
+ "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz",
+ "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==",
+ "dev": true,
+ "license": "ISC",
+ "dependencies": {
+ "is-glob": "^4.0.1"
+ },
+ "engines": {
+ "node": ">= 6"
+ }
+ },
+ "node_modules/fast-json-stable-stringify": {
+ "version": "2.1.0",
+ "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz",
+ "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/fast-levenshtein": {
+ "version": "2.0.6",
+ "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz",
+ "integrity": "sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/fast-uri": {
+ "version": "3.1.2",
+ "resolved": "https://registry.npmjs.org/fast-uri/-/fast-uri-3.1.2.tgz",
+ "integrity": "sha512-rVjf7ArG3LTk+FS6Yw81V1DLuZl1bRbNrev6Tmd/9RaroeeRRJhAt7jg/6YFxbvAQXUCavSoZhPPj6oOx+5KjQ==",
+ "dev": true,
+ "funding": [
+ {
+ "type": "github",
+ "url": "https://github.com/sponsors/fastify"
+ },
+ {
+ "type": "opencollective",
+ "url": "https://opencollective.com/fastify"
+ }
+ ],
+ "license": "BSD-3-Clause",
+ "peer": true
+ },
+ "node_modules/fastq": {
+ "version": "1.20.1",
+ "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.20.1.tgz",
+ "integrity": "sha512-GGToxJ/w1x32s/D2EKND7kTil4n8OVk/9mycTc4VDza13lOvpUZTGX3mFSCtV9ksdGBVzvsyAVLM6mHFThxXxw==",
+ "dev": true,
+ "license": "ISC",
+ "dependencies": {
+ "reusify": "^1.0.4"
+ }
+ },
+ "node_modules/fflate": {
+ "version": "0.7.4",
+ "resolved": "https://registry.npmjs.org/fflate/-/fflate-0.7.4.tgz",
+ "integrity": "sha512-5u2V/CDW15QM1XbbgS+0DfPxVB+jUKhWEKuuFuHncbk3tEEqzmoXL+2KyOFuKGqOnmdIy0/davWF1CkuwtibCw==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/file-entry-cache": {
+ "version": "8.0.0",
+ "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-8.0.0.tgz",
+ "integrity": "sha512-XXTUwCvisa5oacNGRP9SfNtYBNAMi+RPwBFmblZEF7N7swHYQS6/Zfk7SRwx4D5j3CH211YNRco1DEMNVfZCnQ==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "flat-cache": "^4.0.0"
+ },
+ "engines": {
+ "node": ">=16.0.0"
+ }
+ },
+ "node_modules/fill-range": {
+ "version": "7.1.1",
+ "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz",
+ "integrity": "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "to-regex-range": "^5.0.1"
+ },
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/find-up": {
+ "version": "5.0.0",
+ "resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz",
+ "integrity": "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "locate-path": "^6.0.0",
+ "path-exists": "^4.0.0"
+ },
+ "engines": {
+ "node": ">=10"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/flat-cache": {
+ "version": "4.0.1",
+ "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-4.0.1.tgz",
+ "integrity": "sha512-f7ccFPK3SXFHpx15UIGyRJ/FJQctuKZ0zVuN3frBo4HnK3cay9VEW0R6yPYFHC0AgqhukPzKjq22t5DmAyqGyw==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "flatted": "^3.2.9",
+ "keyv": "^4.5.4"
+ },
+ "engines": {
+ "node": ">=16"
+ }
+ },
+ "node_modules/flatted": {
+ "version": "3.4.2",
+ "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.4.2.tgz",
+ "integrity": "sha512-PjDse7RzhcPkIJwy5t7KPWQSZ9cAbzQXcafsetQoD7sOJRQlGikNbx7yZp2OotDnJyrDcbyRq3Ttb18iYOqkxA==",
+ "dev": true,
+ "license": "ISC"
+ },
+ "node_modules/for-each": {
+ "version": "0.3.5",
+ "resolved": "https://registry.npmjs.org/for-each/-/for-each-0.3.5.tgz",
+ "integrity": "sha512-dKx12eRCVIzqCxFGplyFKJMPvLEWgmNtUrpTiJIR5u97zEhRG8ySrtboPHZXx7daLxQVrl643cTzbab2tkQjxg==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "is-callable": "^1.2.7"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/fsevents": {
+ "version": "2.3.3",
+ "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz",
+ "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==",
+ "dev": true,
+ "hasInstallScript": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "darwin"
+ ],
+ "engines": {
+ "node": "^8.16.0 || ^10.6.0 || >=11.0.0"
+ }
+ },
+ "node_modules/function-bind": {
+ "version": "1.1.2",
+ "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz",
+ "integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==",
+ "dev": true,
+ "license": "MIT",
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/function.prototype.name": {
+ "version": "1.1.8",
+ "resolved": "https://registry.npmjs.org/function.prototype.name/-/function.prototype.name-1.1.8.tgz",
+ "integrity": "sha512-e5iwyodOHhbMr/yNrc7fDYG4qlbIvI5gajyzPnb5TCwyhjApznQh1BMFou9b30SevY43gCJKXycoCBjMbsuW0Q==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "call-bind": "^1.0.8",
+ "call-bound": "^1.0.3",
+ "define-properties": "^1.2.1",
+ "functions-have-names": "^1.2.3",
+ "hasown": "^2.0.2",
+ "is-callable": "^1.2.7"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/functions-have-names": {
+ "version": "1.2.3",
+ "resolved": "https://registry.npmjs.org/functions-have-names/-/functions-have-names-1.2.3.tgz",
+ "integrity": "sha512-xckBUXyTIqT97tq2x2AMb+g163b5JFysYk0x4qxNFwbfQkmNZoiRHb6sPzI9/QV33WeuvVYBUIiD4NzNIyqaRQ==",
+ "dev": true,
+ "license": "MIT",
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/generator-function": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/generator-function/-/generator-function-2.0.1.tgz",
+ "integrity": "sha512-SFdFmIJi+ybC0vjlHN0ZGVGHc3lgE0DxPAT0djjVg+kjOnSqclqmj0KQ7ykTOLP6YxoqOvuAODGdcHJn+43q3g==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">= 0.4"
+ }
+ },
+ "node_modules/gensync": {
+ "version": "1.0.0-beta.2",
+ "resolved": "https://registry.npmjs.org/gensync/-/gensync-1.0.0-beta.2.tgz",
+ "integrity": "sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=6.9.0"
+ }
+ },
+ "node_modules/get-intrinsic": {
+ "version": "1.3.0",
+ "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.3.0.tgz",
+ "integrity": "sha512-9fSjSaos/fRIVIp+xSJlE6lfwhES7LNtKaCBIamHsjr2na1BiABJPo0mOjjz8GJDURarmCPGqaiVg5mfjb98CQ==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "call-bind-apply-helpers": "^1.0.2",
+ "es-define-property": "^1.0.1",
+ "es-errors": "^1.3.0",
+ "es-object-atoms": "^1.1.1",
+ "function-bind": "^1.1.2",
+ "get-proto": "^1.0.1",
+ "gopd": "^1.2.0",
+ "has-symbols": "^1.1.0",
+ "hasown": "^2.0.2",
+ "math-intrinsics": "^1.1.0"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/get-proto": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/get-proto/-/get-proto-1.0.1.tgz",
+ "integrity": "sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "dunder-proto": "^1.0.1",
+ "es-object-atoms": "^1.0.0"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ }
+ },
+ "node_modules/get-symbol-description": {
+ "version": "1.1.0",
+ "resolved": "https://registry.npmjs.org/get-symbol-description/-/get-symbol-description-1.1.0.tgz",
+ "integrity": "sha512-w9UMqWwJxHNOvoNzSJ2oPF5wvYcvP7jUvYzhp67yEhTi17ZDBBC1z9pTdGuzjD+EFIqLSYRweZjqfiPzQ06Ebg==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "call-bound": "^1.0.3",
+ "es-errors": "^1.3.0",
+ "get-intrinsic": "^1.2.6"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/get-tsconfig": {
+ "version": "4.14.0",
+ "resolved": "https://registry.npmjs.org/get-tsconfig/-/get-tsconfig-4.14.0.tgz",
+ "integrity": "sha512-yTb+8DXzDREzgvYmh6s9vHsSVCHeC0G3PI5bEXNBHtmshPnO+S5O7qgLEOn0I5QvMy6kpZN8K1NKGyilLb93wA==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "resolve-pkg-maps": "^1.0.0"
+ },
+ "funding": {
+ "url": "https://github.com/privatenumber/get-tsconfig?sponsor=1"
+ }
+ },
+ "node_modules/glob-parent": {
+ "version": "6.0.2",
+ "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz",
+ "integrity": "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==",
+ "dev": true,
+ "license": "ISC",
+ "dependencies": {
+ "is-glob": "^4.0.3"
+ },
+ "engines": {
+ "node": ">=10.13.0"
+ }
+ },
+ "node_modules/glob-to-regexp": {
+ "version": "0.4.1",
+ "resolved": "https://registry.npmjs.org/glob-to-regexp/-/glob-to-regexp-0.4.1.tgz",
+ "integrity": "sha512-lkX1HJXwyMcprw/5YUZc2s7DrpAiHB21/V+E1rHUrVNokkvB6bqMzT0VfV6/86ZNabt1k14YOIaT7nDvOX3Iiw==",
+ "dev": true,
+ "license": "BSD-2-Clause",
+ "peer": true
+ },
+ "node_modules/globals": {
+ "version": "14.0.0",
+ "resolved": "https://registry.npmjs.org/globals/-/globals-14.0.0.tgz",
+ "integrity": "sha512-oahGvuMGQlPw/ivIYBjVSrWAfWLBeku5tpPE2fOPLi+WHffIWbuh2tCjhyQhTBPMf5E9jDEH4FOmTYgYwbKwtQ==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=18"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/globalthis": {
+ "version": "1.0.4",
+ "resolved": "https://registry.npmjs.org/globalthis/-/globalthis-1.0.4.tgz",
+ "integrity": "sha512-DpLKbNU4WylpxJykQujfCcwYWiV/Jhm50Goo0wrVILAv5jOr9d+H+UR3PhSCD2rCCEIg0uc+G+muBTwD54JhDQ==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "define-properties": "^1.2.1",
+ "gopd": "^1.0.1"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/globrex": {
+ "version": "0.1.2",
+ "resolved": "https://registry.npmjs.org/globrex/-/globrex-0.1.2.tgz",
+ "integrity": "sha512-uHJgbwAMwNFf5mLst7IWLNg14x1CkeqglJb/K3doi4dw6q2IvAAmM/Y81kevy83wP+Sst+nutFTYOGg3d1lsxg==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/gopd": {
+ "version": "1.2.0",
+ "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.2.0.tgz",
+ "integrity": "sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/graceful-fs": {
+ "version": "4.2.11",
+ "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz",
+ "integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==",
+ "dev": true,
+ "license": "ISC"
+ },
+ "node_modules/has-bigints": {
+ "version": "1.1.0",
+ "resolved": "https://registry.npmjs.org/has-bigints/-/has-bigints-1.1.0.tgz",
+ "integrity": "sha512-R3pbpkcIqv2Pm3dUwgjclDRVmWpTJW2DcMzcIhEXEx1oh/CEMObMm3KLmRJOdvhM7o4uQBnwr8pzRK2sJWIqfg==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/has-flag": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz",
+ "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/has-property-descriptors": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/has-property-descriptors/-/has-property-descriptors-1.0.2.tgz",
+ "integrity": "sha512-55JNKuIW+vq4Ke1BjOTjM2YctQIvCT7GFzHwmfZPGo5wnrgkid0YQtnAleFSqumZm4az3n2BS+erby5ipJdgrg==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "es-define-property": "^1.0.0"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/has-proto": {
+ "version": "1.2.0",
+ "resolved": "https://registry.npmjs.org/has-proto/-/has-proto-1.2.0.tgz",
+ "integrity": "sha512-KIL7eQPfHQRC8+XluaIw7BHUwwqL19bQn4hzNgdr+1wXoU0KKj6rufu47lhY7KbJR2C6T6+PfyN0Ea7wkSS+qQ==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "dunder-proto": "^1.0.0"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/has-symbols": {
+ "version": "1.1.0",
+ "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.1.0.tgz",
+ "integrity": "sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/has-tostringtag": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/has-tostringtag/-/has-tostringtag-1.0.2.tgz",
+ "integrity": "sha512-NqADB8VjPFLM2V0VvHUewwwsw0ZWBaIdgo+ieHtK3hasLz4qeCRjYcqfB6AQrBggRKppKF8L52/VqdVsO47Dlw==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "has-symbols": "^1.0.3"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/hasown": {
+ "version": "2.0.3",
+ "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.3.tgz",
+ "integrity": "sha512-ej4AhfhfL2Q2zpMmLo7U1Uv9+PyhIZpgQLGT1F9miIGmiCJIoCgSmczFdrc97mWT4kVY72KA+WnnhJ5pghSvSg==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "function-bind": "^1.1.2"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ }
+ },
+ "node_modules/hermes-estree": {
+ "version": "0.25.1",
+ "resolved": "https://registry.npmjs.org/hermes-estree/-/hermes-estree-0.25.1.tgz",
+ "integrity": "sha512-0wUoCcLp+5Ev5pDW2OriHC2MJCbwLwuRx+gAqMTOkGKJJiBCLjtrvy4PWUGn6MIVefecRpzoOZ/UV6iGdOr+Cw==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/hermes-parser": {
+ "version": "0.25.1",
+ "resolved": "https://registry.npmjs.org/hermes-parser/-/hermes-parser-0.25.1.tgz",
+ "integrity": "sha512-6pEjquH3rqaI6cYAXYPcz9MS4rY6R4ngRgrgfDshRptUZIc3lw0MCIJIGDj9++mfySOuPTHB4nrSW99BCvOPIA==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "hermes-estree": "0.25.1"
+ }
+ },
+ "node_modules/hex-rgb": {
+ "version": "4.3.0",
+ "resolved": "https://registry.npmjs.org/hex-rgb/-/hex-rgb-4.3.0.tgz",
+ "integrity": "sha512-Ox1pJVrDCyGHMG9CFg1tmrRUMRPRsAWYc/PinY0XzJU4K7y7vjNoLKIQ7BR5UJMCxNN8EM1MNDmHWA/B3aZUuw==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=6"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/ignore": {
+ "version": "5.3.2",
+ "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.2.tgz",
+ "integrity": "sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">= 4"
+ }
+ },
+ "node_modules/image-size": {
+ "version": "2.0.2",
+ "resolved": "https://registry.npmjs.org/image-size/-/image-size-2.0.2.tgz",
+ "integrity": "sha512-IRqXKlaXwgSMAMtpNzZa1ZAe8m+Sa1770Dhk8VkSsP9LS+iHD62Zd8FQKs8fbPiagBE7BzoFX23cxFnwshpV6w==",
+ "dev": true,
+ "license": "MIT",
+ "bin": {
+ "image-size": "bin/image-size.js"
+ },
+ "engines": {
+ "node": ">=16.x"
+ }
+ },
+ "node_modules/import-fresh": {
+ "version": "3.3.1",
+ "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.1.tgz",
+ "integrity": "sha512-TR3KfrTZTYLPB6jUjfx6MF9WcWrHL9su5TObK4ZkYgBdWKPOFoSoQIdEuTuR82pmtxH2spWG9h6etwfr1pLBqQ==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "parent-module": "^1.0.0",
+ "resolve-from": "^4.0.0"
+ },
+ "engines": {
+ "node": ">=6"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/imurmurhash": {
+ "version": "0.1.4",
+ "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz",
+ "integrity": "sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=0.8.19"
+ }
+ },
+ "node_modules/internal-slot": {
+ "version": "1.1.0",
+ "resolved": "https://registry.npmjs.org/internal-slot/-/internal-slot-1.1.0.tgz",
+ "integrity": "sha512-4gd7VpWNQNB4UKKCFFVcp1AVv+FMOgs9NKzjHKusc8jTMhd5eL1NqQqOpE0KzMds804/yHlglp3uxgluOqAPLw==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "es-errors": "^1.3.0",
+ "hasown": "^2.0.2",
+ "side-channel": "^1.1.0"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ }
+ },
+ "node_modules/ipaddr.js": {
+ "version": "2.4.0",
+ "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-2.4.0.tgz",
+ "integrity": "sha512-9VGk3HGanVE6JoZXHiCpnGy5X0jYDnN4EA4lntFPj+1vIWlFhIylq2CrrCOJH9EAhc5CYhq18F2Av2tgoAPsYQ==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">= 10"
+ }
+ },
+ "node_modules/is-array-buffer": {
+ "version": "3.0.5",
+ "resolved": "https://registry.npmjs.org/is-array-buffer/-/is-array-buffer-3.0.5.tgz",
+ "integrity": "sha512-DDfANUiiG2wC1qawP66qlTugJeL5HyzMpfr8lLK+jMQirGzNod0B12cFB/9q838Ru27sBwfw78/rdoU7RERz6A==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "call-bind": "^1.0.8",
+ "call-bound": "^1.0.3",
+ "get-intrinsic": "^1.2.6"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/is-async-function": {
+ "version": "2.1.1",
+ "resolved": "https://registry.npmjs.org/is-async-function/-/is-async-function-2.1.1.tgz",
+ "integrity": "sha512-9dgM/cZBnNvjzaMYHVoxxfPj2QXt22Ev7SuuPrs+xav0ukGB0S6d4ydZdEiM48kLx5kDV+QBPrpVnFyefL8kkQ==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "async-function": "^1.0.0",
+ "call-bound": "^1.0.3",
+ "get-proto": "^1.0.1",
+ "has-tostringtag": "^1.0.2",
+ "safe-regex-test": "^1.1.0"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/is-bigint": {
+ "version": "1.1.0",
+ "resolved": "https://registry.npmjs.org/is-bigint/-/is-bigint-1.1.0.tgz",
+ "integrity": "sha512-n4ZT37wG78iz03xPRKJrHTdZbe3IicyucEtdRsV5yglwc3GyUfbAfpSeD0FJ41NbUNSt5wbhqfp1fS+BgnvDFQ==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "has-bigints": "^1.0.2"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/is-boolean-object": {
+ "version": "1.2.2",
+ "resolved": "https://registry.npmjs.org/is-boolean-object/-/is-boolean-object-1.2.2.tgz",
+ "integrity": "sha512-wa56o2/ElJMYqjCjGkXri7it5FbebW5usLw/nPmCMs5DeZ7eziSYZhSmPRn0txqeW4LnAmQQU7FgqLpsEFKM4A==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "call-bound": "^1.0.3",
+ "has-tostringtag": "^1.0.2"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/is-bun-module": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/is-bun-module/-/is-bun-module-2.0.0.tgz",
+ "integrity": "sha512-gNCGbnnnnFAUGKeZ9PdbyeGYJqewpmc2aKHUEMO5nQPWU9lOmv7jcmQIv+qHD8fXW6W7qfuCwX4rY9LNRjXrkQ==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "semver": "^7.7.1"
+ }
+ },
+ "node_modules/is-bun-module/node_modules/semver": {
+ "version": "7.8.0",
+ "resolved": "https://registry.npmjs.org/semver/-/semver-7.8.0.tgz",
+ "integrity": "sha512-AcM7dV/5ul4EekoQ29Agm5vri8JNqRyj39o0qpX6vDF2GZrtutZl5RwgD1XnZjiTAfncsJhMI48QQH3sN87YNA==",
+ "dev": true,
+ "license": "ISC",
+ "bin": {
+ "semver": "bin/semver.js"
+ },
+ "engines": {
+ "node": ">=10"
+ }
+ },
+ "node_modules/is-callable": {
+ "version": "1.2.7",
+ "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.2.7.tgz",
+ "integrity": "sha512-1BC0BVFhS/p0qtw6enp8e+8OD0UrK0oFLztSjNzhcKA3WDuJxxAPXzPuPtKkjEY9UUoEWlX/8fgKeu2S8i9JTA==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/is-core-module": {
+ "version": "2.16.2",
+ "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.16.2.tgz",
+ "integrity": "sha512-evOr8xfXKxE6qSR0hSXL2r3sd7ALj8+7jQEUvPYcm5sgZFdJ+AYzT6yNmJenvIYQBgIGwfwz08sL8zoL7yq2BA==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "hasown": "^2.0.3"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/is-data-view": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/is-data-view/-/is-data-view-1.0.2.tgz",
+ "integrity": "sha512-RKtWF8pGmS87i2D6gqQu/l7EYRlVdfzemCJN/P3UOs//x1QE7mfhvzHIApBTRf7axvT6DMGwSwBXYCT0nfB9xw==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "call-bound": "^1.0.2",
+ "get-intrinsic": "^1.2.6",
+ "is-typed-array": "^1.1.13"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/is-date-object": {
+ "version": "1.1.0",
+ "resolved": "https://registry.npmjs.org/is-date-object/-/is-date-object-1.1.0.tgz",
+ "integrity": "sha512-PwwhEakHVKTdRNVOw+/Gyh0+MzlCl4R6qKvkhuvLtPMggI1WAHt9sOwZxQLSGpUaDnrdyDsomoRgNnCfKNSXXg==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "call-bound": "^1.0.2",
+ "has-tostringtag": "^1.0.2"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/is-extglob": {
+ "version": "2.1.1",
+ "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz",
+ "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/is-finalizationregistry": {
+ "version": "1.1.1",
+ "resolved": "https://registry.npmjs.org/is-finalizationregistry/-/is-finalizationregistry-1.1.1.tgz",
+ "integrity": "sha512-1pC6N8qWJbWoPtEjgcL2xyhQOP491EQjeUo3qTKcmV8YSDDJrOepfG8pcC7h/QgnQHYSv0mJ3Z/ZWxmatVrysg==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "call-bound": "^1.0.3"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/is-generator-function": {
+ "version": "1.1.2",
+ "resolved": "https://registry.npmjs.org/is-generator-function/-/is-generator-function-1.1.2.tgz",
+ "integrity": "sha512-upqt1SkGkODW9tsGNG5mtXTXtECizwtS2kA161M+gJPc1xdb/Ax629af6YrTwcOeQHbewrPNlE5Dx7kzvXTizA==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "call-bound": "^1.0.4",
+ "generator-function": "^2.0.0",
+ "get-proto": "^1.0.1",
+ "has-tostringtag": "^1.0.2",
+ "safe-regex-test": "^1.1.0"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/is-glob": {
+ "version": "4.0.3",
+ "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz",
+ "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "is-extglob": "^2.1.1"
+ },
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/is-map": {
+ "version": "2.0.3",
+ "resolved": "https://registry.npmjs.org/is-map/-/is-map-2.0.3.tgz",
+ "integrity": "sha512-1Qed0/Hr2m+YqxnM09CjA2d/i6YZNfF6R2oRAOj36eUdS6qIV/huPJNSEpKbupewFs+ZsJlxsjjPbc0/afW6Lw==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/is-negative-zero": {
+ "version": "2.0.3",
+ "resolved": "https://registry.npmjs.org/is-negative-zero/-/is-negative-zero-2.0.3.tgz",
+ "integrity": "sha512-5KoIu2Ngpyek75jXodFvnafB6DJgr3u8uuK0LEZJjrU19DrMD3EVERaR8sjz8CCGgpZvxPl9SuE1GMVPFHx1mw==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/is-number": {
+ "version": "7.0.0",
+ "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz",
+ "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=0.12.0"
+ }
+ },
+ "node_modules/is-number-object": {
+ "version": "1.1.1",
+ "resolved": "https://registry.npmjs.org/is-number-object/-/is-number-object-1.1.1.tgz",
+ "integrity": "sha512-lZhclumE1G6VYD8VHe35wFaIif+CTy5SJIi5+3y4psDgWu4wPDoBhF8NxUOinEc7pHgiTsT6MaBb92rKhhD+Xw==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "call-bound": "^1.0.3",
+ "has-tostringtag": "^1.0.2"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/is-regex": {
+ "version": "1.2.1",
+ "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.2.1.tgz",
+ "integrity": "sha512-MjYsKHO5O7mCsmRGxWcLWheFqN9DJ/2TmngvjKXihe6efViPqc274+Fx/4fYj/r03+ESvBdTXK0V6tA3rgez1g==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "call-bound": "^1.0.2",
+ "gopd": "^1.2.0",
+ "has-tostringtag": "^1.0.2",
+ "hasown": "^2.0.2"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/is-set": {
+ "version": "2.0.3",
+ "resolved": "https://registry.npmjs.org/is-set/-/is-set-2.0.3.tgz",
+ "integrity": "sha512-iPAjerrse27/ygGLxw+EBR9agv9Y6uLeYVJMu+QNCoouJ1/1ri0mGrcWpfCqFZuzzx3WjtwxG098X+n4OuRkPg==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/is-shared-array-buffer": {
+ "version": "1.0.4",
+ "resolved": "https://registry.npmjs.org/is-shared-array-buffer/-/is-shared-array-buffer-1.0.4.tgz",
+ "integrity": "sha512-ISWac8drv4ZGfwKl5slpHG9OwPNty4jOWPRIhBpxOoD+hqITiwuipOQ2bNthAzwA3B4fIjO4Nln74N0S9byq8A==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "call-bound": "^1.0.3"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/is-string": {
+ "version": "1.1.1",
+ "resolved": "https://registry.npmjs.org/is-string/-/is-string-1.1.1.tgz",
+ "integrity": "sha512-BtEeSsoaQjlSPBemMQIrY1MY0uM6vnS1g5fmufYOtnxLGUZM2178PKbhsk7Ffv58IX+ZtcvoGwccYsh0PglkAA==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "call-bound": "^1.0.3",
+ "has-tostringtag": "^1.0.2"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/is-symbol": {
+ "version": "1.1.1",
+ "resolved": "https://registry.npmjs.org/is-symbol/-/is-symbol-1.1.1.tgz",
+ "integrity": "sha512-9gGx6GTtCQM73BgmHQXfDmLtfjjTUDSyoxTCbp5WtoixAhfgsDirWIcVQ/IHpvI5Vgd5i/J5F7B9cN/WlVbC/w==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "call-bound": "^1.0.2",
+ "has-symbols": "^1.1.0",
+ "safe-regex-test": "^1.1.0"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/is-typed-array": {
+ "version": "1.1.15",
+ "resolved": "https://registry.npmjs.org/is-typed-array/-/is-typed-array-1.1.15.tgz",
+ "integrity": "sha512-p3EcsicXjit7SaskXHs1hA91QxgTw46Fv6EFKKGS5DRFLD8yKnohjF3hxoju94b/OcMZoQukzpPpBE9uLVKzgQ==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "which-typed-array": "^1.1.16"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/is-weakmap": {
+ "version": "2.0.2",
+ "resolved": "https://registry.npmjs.org/is-weakmap/-/is-weakmap-2.0.2.tgz",
+ "integrity": "sha512-K5pXYOm9wqY1RgjpL3YTkF39tni1XajUIkawTLUo9EZEVUFga5gSQJF8nNS7ZwJQ02y+1YCNYcMh+HIf1ZqE+w==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/is-weakref": {
+ "version": "1.1.1",
+ "resolved": "https://registry.npmjs.org/is-weakref/-/is-weakref-1.1.1.tgz",
+ "integrity": "sha512-6i9mGWSlqzNMEqpCp93KwRS1uUOodk2OJ6b+sq7ZPDSy2WuI5NFIxp/254TytR8ftefexkWn5xNiHUNpPOfSew==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "call-bound": "^1.0.3"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/is-weakset": {
+ "version": "2.0.4",
+ "resolved": "https://registry.npmjs.org/is-weakset/-/is-weakset-2.0.4.tgz",
+ "integrity": "sha512-mfcwb6IzQyOKTs84CQMrOwW4gQcaTOAWJ0zzJCl2WSPDrWk/OzDaImWFH3djXhb24g4eudZfLRozAvPGw4d9hQ==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "call-bound": "^1.0.3",
+ "get-intrinsic": "^1.2.6"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/isarray": {
+ "version": "2.0.5",
+ "resolved": "https://registry.npmjs.org/isarray/-/isarray-2.0.5.tgz",
+ "integrity": "sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/isexe": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz",
+ "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==",
+ "dev": true,
+ "license": "ISC"
+ },
+ "node_modules/iterator.prototype": {
+ "version": "1.1.5",
+ "resolved": "https://registry.npmjs.org/iterator.prototype/-/iterator.prototype-1.1.5.tgz",
+ "integrity": "sha512-H0dkQoCa3b2VEeKQBOxFph+JAbcrQdE7KC0UkqwpLmv2EC4P41QXP+rqo9wYodACiG5/WM5s9oDApTU8utwj9g==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "define-data-property": "^1.1.4",
+ "es-object-atoms": "^1.0.0",
+ "get-intrinsic": "^1.2.6",
+ "get-proto": "^1.0.0",
+ "has-symbols": "^1.1.0",
+ "set-function-name": "^2.0.2"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ }
+ },
+ "node_modules/jest-worker": {
+ "version": "27.5.1",
+ "resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-27.5.1.tgz",
+ "integrity": "sha512-7vuh85V5cdDofPyxn58nrPjBktZo0u9x1g8WtjQol+jZDaE+fhN+cIvTj11GndBnMnyfrUOG1sZQxCdjKh+DKg==",
+ "dev": true,
+ "license": "MIT",
+ "peer": true,
+ "dependencies": {
+ "@types/node": "*",
+ "merge-stream": "^2.0.0",
+ "supports-color": "^8.0.0"
+ },
+ "engines": {
+ "node": ">= 10.13.0"
+ }
+ },
+ "node_modules/jest-worker/node_modules/supports-color": {
+ "version": "8.1.1",
+ "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz",
+ "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==",
+ "dev": true,
+ "license": "MIT",
+ "peer": true,
+ "dependencies": {
+ "has-flag": "^4.0.0"
+ },
+ "engines": {
+ "node": ">=10"
+ },
+ "funding": {
+ "url": "https://github.com/chalk/supports-color?sponsor=1"
+ }
+ },
+ "node_modules/jiti": {
+ "version": "2.7.0",
+ "resolved": "https://registry.npmjs.org/jiti/-/jiti-2.7.0.tgz",
+ "integrity": "sha512-AC/7JofJvZGrrneWNaEnJeOLUx+JlGt7tNa0wZiRPT4MY1wmfKjt2+6O2p2uz2+skll8OZZmJMNqeke7kKbNgQ==",
+ "dev": true,
+ "license": "MIT",
+ "bin": {
+ "jiti": "lib/jiti-cli.mjs"
+ }
+ },
+ "node_modules/js-tokens": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz",
+ "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/js-yaml": {
+ "version": "4.1.1",
+ "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.1.tgz",
+ "integrity": "sha512-qQKT4zQxXl8lLwBtHMWwaTcGfFOZviOJet3Oy/xmGk2gZH677CJM9EvtfdSkgWcATZhj/55JZ0rmy3myCT5lsA==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "argparse": "^2.0.1"
+ },
+ "bin": {
+ "js-yaml": "bin/js-yaml.js"
+ }
+ },
+ "node_modules/jsesc": {
+ "version": "3.1.0",
+ "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-3.1.0.tgz",
+ "integrity": "sha512-/sM3dO2FOzXjKQhJuo0Q173wf2KOo8t4I8vHy6lF9poUp7bKT0/NHE8fPX23PwfhnykfqnC2xRxOnVw5XuGIaA==",
+ "dev": true,
+ "license": "MIT",
+ "bin": {
+ "jsesc": "bin/jsesc"
+ },
+ "engines": {
+ "node": ">=6"
+ }
+ },
+ "node_modules/json-buffer": {
+ "version": "3.0.1",
+ "resolved": "https://registry.npmjs.org/json-buffer/-/json-buffer-3.0.1.tgz",
+ "integrity": "sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/json-schema-traverse": {
+ "version": "0.4.1",
+ "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz",
+ "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/json-stable-stringify-without-jsonify": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz",
+ "integrity": "sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/json5": {
+ "version": "2.2.3",
+ "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.3.tgz",
+ "integrity": "sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==",
+ "dev": true,
+ "license": "MIT",
+ "bin": {
+ "json5": "lib/cli.js"
+ },
+ "engines": {
+ "node": ">=6"
+ }
+ },
+ "node_modules/jsx-ast-utils": {
+ "version": "3.3.5",
+ "resolved": "https://registry.npmjs.org/jsx-ast-utils/-/jsx-ast-utils-3.3.5.tgz",
+ "integrity": "sha512-ZZow9HBI5O6EPgSJLUb8n2NKgmVWTwCvHGwFuJlMjvLFqlGG6pjirPhtdsseaLZjSibD8eegzmYpUZwoIlj2cQ==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "array-includes": "^3.1.6",
+ "array.prototype.flat": "^1.3.1",
+ "object.assign": "^4.1.4",
+ "object.values": "^1.1.6"
+ },
+ "engines": {
+ "node": ">=4.0"
+ }
+ },
+ "node_modules/keyv": {
+ "version": "4.5.4",
+ "resolved": "https://registry.npmjs.org/keyv/-/keyv-4.5.4.tgz",
+ "integrity": "sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "json-buffer": "3.0.1"
+ }
+ },
+ "node_modules/kleur": {
+ "version": "4.1.5",
+ "resolved": "https://registry.npmjs.org/kleur/-/kleur-4.1.5.tgz",
+ "integrity": "sha512-o+NO+8WrRiQEE4/7nwRJhN1HWpVmJm511pBHUxPLtp0BUISzlBplORYSmTclCnJvQq2tKu/sgl3xVpkc7ZWuQQ==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=6"
+ }
+ },
+ "node_modules/language-subtag-registry": {
+ "version": "0.3.23",
+ "resolved": "https://registry.npmjs.org/language-subtag-registry/-/language-subtag-registry-0.3.23.tgz",
+ "integrity": "sha512-0K65Lea881pHotoGEa5gDlMxt3pctLi2RplBb7Ezh4rRdLEOtgi7n4EwK9lamnUCkKBqaeKRVebTq6BAxSkpXQ==",
+ "dev": true,
+ "license": "CC0-1.0"
+ },
+ "node_modules/language-tags": {
+ "version": "1.0.9",
+ "resolved": "https://registry.npmjs.org/language-tags/-/language-tags-1.0.9.tgz",
+ "integrity": "sha512-MbjN408fEndfiQXbFQ1vnd+1NoLDsnQW41410oQBXiyXDMYH5z505juWa4KUE1LqxRC7DgOgZDbKLxHIwm27hA==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "language-subtag-registry": "^0.3.20"
+ },
+ "engines": {
+ "node": ">=0.10"
+ }
+ },
+ "node_modules/levn": {
+ "version": "0.4.1",
+ "resolved": "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz",
+ "integrity": "sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "prelude-ls": "^1.2.1",
+ "type-check": "~0.4.0"
+ },
+ "engines": {
+ "node": ">= 0.8.0"
+ }
+ },
+ "node_modules/lightningcss": {
+ "version": "1.31.1",
+ "resolved": "https://registry.npmjs.org/lightningcss/-/lightningcss-1.31.1.tgz",
+ "integrity": "sha512-l51N2r93WmGUye3WuFoN5k10zyvrVs0qfKBhyC5ogUQ6Ew6JUSswh78mbSO+IU3nTWsyOArqPCcShdQSadghBQ==",
+ "dev": true,
+ "license": "MPL-2.0",
+ "dependencies": {
+ "detect-libc": "^2.0.3"
+ },
+ "engines": {
+ "node": ">= 12.0.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/parcel"
+ },
+ "optionalDependencies": {
+ "lightningcss-android-arm64": "1.31.1",
+ "lightningcss-darwin-arm64": "1.31.1",
+ "lightningcss-darwin-x64": "1.31.1",
+ "lightningcss-freebsd-x64": "1.31.1",
+ "lightningcss-linux-arm-gnueabihf": "1.31.1",
+ "lightningcss-linux-arm64-gnu": "1.31.1",
+ "lightningcss-linux-arm64-musl": "1.31.1",
+ "lightningcss-linux-x64-gnu": "1.31.1",
+ "lightningcss-linux-x64-musl": "1.31.1",
+ "lightningcss-win32-arm64-msvc": "1.31.1",
+ "lightningcss-win32-x64-msvc": "1.31.1"
+ }
+ },
+ "node_modules/lightningcss-android-arm64": {
+ "version": "1.31.1",
+ "resolved": "https://registry.npmjs.org/lightningcss-android-arm64/-/lightningcss-android-arm64-1.31.1.tgz",
+ "integrity": "sha512-HXJF3x8w9nQ4jbXRiNppBCqeZPIAfUo8zE/kOEGbW5NZvGc/K7nMxbhIr+YlFlHW5mpbg/YFPdbnCh1wAXCKFg==",
+ "cpu": [
+ "arm64"
+ ],
+ "dev": true,
+ "license": "MPL-2.0",
+ "optional": true,
+ "os": [
+ "android"
+ ],
+ "engines": {
+ "node": ">= 12.0.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/parcel"
+ }
+ },
+ "node_modules/lightningcss-darwin-arm64": {
+ "version": "1.31.1",
+ "resolved": "https://registry.npmjs.org/lightningcss-darwin-arm64/-/lightningcss-darwin-arm64-1.31.1.tgz",
+ "integrity": "sha512-02uTEqf3vIfNMq3h/z2cJfcOXnQ0GRwQrkmPafhueLb2h7mqEidiCzkE4gBMEH65abHRiQvhdcQ+aP0D0g67sg==",
+ "cpu": [
+ "arm64"
+ ],
+ "dev": true,
+ "license": "MPL-2.0",
+ "optional": true,
+ "os": [
+ "darwin"
+ ],
+ "engines": {
+ "node": ">= 12.0.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/parcel"
+ }
+ },
+ "node_modules/lightningcss-darwin-x64": {
+ "version": "1.31.1",
+ "resolved": "https://registry.npmjs.org/lightningcss-darwin-x64/-/lightningcss-darwin-x64-1.31.1.tgz",
+ "integrity": "sha512-1ObhyoCY+tGxtsz1lSx5NXCj3nirk0Y0kB/g8B8DT+sSx4G9djitg9ejFnjb3gJNWo7qXH4DIy2SUHvpoFwfTA==",
+ "cpu": [
+ "x64"
+ ],
+ "dev": true,
+ "license": "MPL-2.0",
+ "optional": true,
+ "os": [
+ "darwin"
+ ],
+ "engines": {
+ "node": ">= 12.0.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/parcel"
+ }
+ },
+ "node_modules/lightningcss-freebsd-x64": {
+ "version": "1.31.1",
+ "resolved": "https://registry.npmjs.org/lightningcss-freebsd-x64/-/lightningcss-freebsd-x64-1.31.1.tgz",
+ "integrity": "sha512-1RINmQKAItO6ISxYgPwszQE1BrsVU5aB45ho6O42mu96UiZBxEXsuQ7cJW4zs4CEodPUioj/QrXW1r9pLUM74A==",
+ "cpu": [
+ "x64"
+ ],
+ "dev": true,
+ "license": "MPL-2.0",
+ "optional": true,
+ "os": [
+ "freebsd"
+ ],
+ "engines": {
+ "node": ">= 12.0.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/parcel"
+ }
+ },
+ "node_modules/lightningcss-linux-arm-gnueabihf": {
+ "version": "1.31.1",
+ "resolved": "https://registry.npmjs.org/lightningcss-linux-arm-gnueabihf/-/lightningcss-linux-arm-gnueabihf-1.31.1.tgz",
+ "integrity": "sha512-OOCm2//MZJ87CdDK62rZIu+aw9gBv4azMJuA8/KB74wmfS3lnC4yoPHm0uXZ/dvNNHmnZnB8XLAZzObeG0nS1g==",
+ "cpu": [
+ "arm"
+ ],
+ "dev": true,
+ "license": "MPL-2.0",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">= 12.0.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/parcel"
+ }
+ },
+ "node_modules/lightningcss-linux-arm64-gnu": {
+ "version": "1.31.1",
+ "resolved": "https://registry.npmjs.org/lightningcss-linux-arm64-gnu/-/lightningcss-linux-arm64-gnu-1.31.1.tgz",
+ "integrity": "sha512-WKyLWztD71rTnou4xAD5kQT+982wvca7E6QoLpoawZ1gP9JM0GJj4Tp5jMUh9B3AitHbRZ2/H3W5xQmdEOUlLg==",
+ "cpu": [
+ "arm64"
+ ],
+ "dev": true,
+ "license": "MPL-2.0",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">= 12.0.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/parcel"
+ }
+ },
+ "node_modules/lightningcss-linux-arm64-musl": {
+ "version": "1.31.1",
+ "resolved": "https://registry.npmjs.org/lightningcss-linux-arm64-musl/-/lightningcss-linux-arm64-musl-1.31.1.tgz",
+ "integrity": "sha512-mVZ7Pg2zIbe3XlNbZJdjs86YViQFoJSpc41CbVmKBPiGmC4YrfeOyz65ms2qpAobVd7WQsbW4PdsSJEMymyIMg==",
+ "cpu": [
+ "arm64"
+ ],
+ "dev": true,
+ "license": "MPL-2.0",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">= 12.0.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/parcel"
+ }
+ },
+ "node_modules/lightningcss-linux-x64-gnu": {
+ "version": "1.31.1",
+ "resolved": "https://registry.npmjs.org/lightningcss-linux-x64-gnu/-/lightningcss-linux-x64-gnu-1.31.1.tgz",
+ "integrity": "sha512-xGlFWRMl+0KvUhgySdIaReQdB4FNudfUTARn7q0hh/V67PVGCs3ADFjw+6++kG1RNd0zdGRlEKa+T13/tQjPMA==",
+ "cpu": [
+ "x64"
+ ],
+ "dev": true,
+ "license": "MPL-2.0",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">= 12.0.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/parcel"
+ }
+ },
+ "node_modules/lightningcss-linux-x64-musl": {
+ "version": "1.31.1",
+ "resolved": "https://registry.npmjs.org/lightningcss-linux-x64-musl/-/lightningcss-linux-x64-musl-1.31.1.tgz",
+ "integrity": "sha512-eowF8PrKHw9LpoZii5tdZwnBcYDxRw2rRCyvAXLi34iyeYfqCQNA9rmUM0ce62NlPhCvof1+9ivRaTY6pSKDaA==",
+ "cpu": [
+ "x64"
+ ],
+ "dev": true,
+ "license": "MPL-2.0",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">= 12.0.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/parcel"
+ }
+ },
+ "node_modules/lightningcss-win32-arm64-msvc": {
+ "version": "1.31.1",
+ "resolved": "https://registry.npmjs.org/lightningcss-win32-arm64-msvc/-/lightningcss-win32-arm64-msvc-1.31.1.tgz",
+ "integrity": "sha512-aJReEbSEQzx1uBlQizAOBSjcmr9dCdL3XuC/6HLXAxmtErsj2ICo5yYggg1qOODQMtnjNQv2UHb9NpOuFtYe4w==",
+ "cpu": [
+ "arm64"
+ ],
+ "dev": true,
+ "license": "MPL-2.0",
+ "optional": true,
+ "os": [
+ "win32"
+ ],
+ "engines": {
+ "node": ">= 12.0.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/parcel"
+ }
+ },
+ "node_modules/lightningcss-win32-x64-msvc": {
+ "version": "1.31.1",
+ "resolved": "https://registry.npmjs.org/lightningcss-win32-x64-msvc/-/lightningcss-win32-x64-msvc-1.31.1.tgz",
+ "integrity": "sha512-I9aiFrbd7oYHwlnQDqr1Roz+fTz61oDDJX7n9tYF9FJymH1cIN1DtKw3iYt6b8WZgEjoNwVSncwF4wx/ZedMhw==",
+ "cpu": [
+ "x64"
+ ],
+ "dev": true,
+ "license": "MPL-2.0",
+ "optional": true,
+ "os": [
+ "win32"
+ ],
+ "engines": {
+ "node": ">= 12.0.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/parcel"
+ }
+ },
+ "node_modules/linebreak": {
+ "version": "1.1.0",
+ "resolved": "https://registry.npmjs.org/linebreak/-/linebreak-1.1.0.tgz",
+ "integrity": "sha512-MHp03UImeVhB7XZtjd0E4n6+3xr5Dq/9xI/5FptGk5FrbDR3zagPa2DS6U8ks/3HjbKWG9Q1M2ufOzxV2qLYSQ==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "base64-js": "0.0.8",
+ "unicode-trie": "^2.0.0"
+ }
+ },
+ "node_modules/loader-runner": {
+ "version": "4.3.2",
+ "resolved": "https://registry.npmjs.org/loader-runner/-/loader-runner-4.3.2.tgz",
+ "integrity": "sha512-DFEqQ3ihfS9blba08cLfYf1NRAIEm+dDjic073DRDc3/JspI/8wYmtDsHwd3+4hwvdxSK7PGaElfTmm0awWJ4w==",
+ "dev": true,
+ "license": "MIT",
+ "peer": true,
+ "engines": {
+ "node": ">=6.11.5"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/webpack"
+ }
+ },
+ "node_modules/locate-path": {
+ "version": "6.0.0",
+ "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz",
+ "integrity": "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "p-locate": "^5.0.0"
+ },
+ "engines": {
+ "node": ">=10"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/lodash.merge": {
+ "version": "4.6.2",
+ "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz",
+ "integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/loose-envify": {
+ "version": "1.4.0",
+ "resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz",
+ "integrity": "sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "js-tokens": "^3.0.0 || ^4.0.0"
+ },
+ "bin": {
+ "loose-envify": "cli.js"
+ }
+ },
+ "node_modules/lru-cache": {
+ "version": "5.1.1",
+ "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz",
+ "integrity": "sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==",
+ "dev": true,
+ "license": "ISC",
+ "dependencies": {
+ "yallist": "^3.0.2"
+ }
+ },
+ "node_modules/magic-string": {
+ "version": "0.30.21",
+ "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.21.tgz",
+ "integrity": "sha512-vd2F4YUyEXKGcLHoq+TEyCjxueSeHnFxyyjNp80yg0XV4vUhnDer/lvvlqM/arB5bXQN5K2/3oinyCRyx8T2CQ==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@jridgewell/sourcemap-codec": "^1.5.5"
+ }
+ },
+ "node_modules/math-intrinsics": {
+ "version": "1.1.0",
+ "resolved": "https://registry.npmjs.org/math-intrinsics/-/math-intrinsics-1.1.0.tgz",
+ "integrity": "sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">= 0.4"
+ }
+ },
+ "node_modules/merge-stream": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/merge-stream/-/merge-stream-2.0.0.tgz",
+ "integrity": "sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==",
+ "dev": true,
+ "license": "MIT",
+ "peer": true
+ },
+ "node_modules/merge2": {
+ "version": "1.4.1",
+ "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz",
+ "integrity": "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">= 8"
+ }
+ },
+ "node_modules/micromatch": {
+ "version": "4.0.8",
+ "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.8.tgz",
+ "integrity": "sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "braces": "^3.0.3",
+ "picomatch": "^2.3.1"
+ },
+ "engines": {
+ "node": ">=8.6"
+ }
+ },
+ "node_modules/mime-db": {
+ "version": "1.54.0",
+ "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.54.0.tgz",
+ "integrity": "sha512-aU5EJuIN2WDemCcAp2vFBfp/m4EAhWJnUNSSw0ixs7/kXbd6Pg64EmwJkNdFhB8aWt1sH2CTXrLxo/iAGV3oPQ==",
+ "dev": true,
+ "license": "MIT",
+ "peer": true,
+ "engines": {
+ "node": ">= 0.6"
+ }
+ },
+ "node_modules/miniflare": {
+ "version": "4.20260515.0",
+ "resolved": "https://registry.npmjs.org/miniflare/-/miniflare-4.20260515.0.tgz",
+ "integrity": "sha512-2j0oQWizk1Eu4Cm8tDX7Z+Nsjd0nebIj1TQcQ+Oy1QKeo0Ay9+bdn8wfLAtOj9znDCybDCUlnS1+nYvKXEdfNg==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@cspotcode/source-map-support": "0.8.1",
+ "sharp": "^0.34.5",
+ "undici": "7.24.8",
+ "workerd": "1.20260515.1",
+ "ws": "8.18.0",
+ "youch": "4.1.0-beta.10"
+ },
+ "bin": {
+ "miniflare": "bootstrap.js"
+ },
+ "engines": {
+ "node": ">=22.0.0"
+ }
+ },
+ "node_modules/minimatch": {
+ "version": "3.1.5",
+ "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.5.tgz",
+ "integrity": "sha512-VgjWUsnnT6n+NUk6eZq77zeFdpW2LWDzP6zFGrCbHXiYNul5Dzqk2HHQ5uFH2DNW5Xbp8+jVzaeNt94ssEEl4w==",
+ "dev": true,
+ "license": "ISC",
+ "dependencies": {
+ "brace-expansion": "^1.1.7"
+ },
+ "engines": {
+ "node": "*"
+ }
+ },
+ "node_modules/minimist": {
+ "version": "1.2.8",
+ "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.8.tgz",
+ "integrity": "sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==",
+ "dev": true,
+ "license": "MIT",
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/ms": {
+ "version": "2.1.3",
+ "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz",
+ "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/nanoid": {
+ "version": "3.3.16",
+ "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.16.tgz",
+ "integrity": "sha512-bzlKTyNJ7+LdGIIwy8ijFpIqEQIvafahV7eYykJ8Cvh42EdJeODoJ6gUJXpQJvej1BddH8OqTXZNE/KfbWAu8Q==",
+ "funding": [
+ {
+ "type": "github",
+ "url": "https://github.com/sponsors/ai"
+ }
+ ],
+ "license": "MIT",
+ "bin": {
+ "nanoid": "bin/nanoid.cjs"
+ },
+ "engines": {
+ "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1"
+ }
+ },
+ "node_modules/napi-postinstall": {
+ "version": "0.3.4",
+ "resolved": "https://registry.npmjs.org/napi-postinstall/-/napi-postinstall-0.3.4.tgz",
+ "integrity": "sha512-PHI5f1O0EP5xJ9gQmFGMS6IZcrVvTjpXjz7Na41gTE7eE2hK11lg04CECCYEEjdc17EV4DO+fkGEtt7TpTaTiQ==",
+ "dev": true,
+ "license": "MIT",
+ "bin": {
+ "napi-postinstall": "lib/cli.js"
+ },
+ "engines": {
+ "node": "^12.20.0 || ^14.18.0 || >=16.0.0"
+ },
+ "funding": {
+ "url": "https://opencollective.com/napi-postinstall"
+ }
+ },
+ "node_modules/natural-compare": {
+ "version": "1.4.0",
+ "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz",
+ "integrity": "sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/neo-async": {
+ "version": "2.6.2",
+ "resolved": "https://registry.npmjs.org/neo-async/-/neo-async-2.6.2.tgz",
+ "integrity": "sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/next": {
+ "version": "16.2.12",
+ "resolved": "https://registry.npmjs.org/next/-/next-16.2.12.tgz",
+ "integrity": "sha512-iD59eYQWmbFcEbX7v/acG5DRym9iw1DdaPoD0WTA920naWsE25wShzJW4+UvAs8MK9EC2kBfIH6vtto1H1PHGw==",
+ "license": "MIT",
+ "dependencies": {
+ "@next/env": "16.2.12",
+ "@swc/helpers": "0.5.15",
+ "baseline-browser-mapping": "^2.9.19",
+ "caniuse-lite": "^1.0.30001579",
+ "postcss": "8.4.31",
+ "styled-jsx": "5.1.6"
+ },
+ "bin": {
+ "next": "dist/bin/next"
+ },
+ "engines": {
+ "node": ">=20.9.0"
+ },
+ "optionalDependencies": {
+ "@next/swc-darwin-arm64": "16.2.12",
+ "@next/swc-darwin-x64": "16.2.12",
+ "@next/swc-linux-arm64-gnu": "16.2.12",
+ "@next/swc-linux-arm64-musl": "16.2.12",
+ "@next/swc-linux-x64-gnu": "16.2.12",
+ "@next/swc-linux-x64-musl": "16.2.12",
+ "@next/swc-win32-arm64-msvc": "16.2.12",
+ "@next/swc-win32-x64-msvc": "16.2.12",
+ "sharp": "^0.34.5"
+ },
+ "peerDependencies": {
+ "@opentelemetry/api": "^1.1.0",
+ "@playwright/test": "^1.51.1",
+ "babel-plugin-react-compiler": "*",
+ "react": "^18.2.0 || 19.0.0-rc-de68d2f4-20241204 || ^19.0.0",
+ "react-dom": "^18.2.0 || 19.0.0-rc-de68d2f4-20241204 || ^19.0.0",
+ "sass": "^1.3.0"
+ },
+ "peerDependenciesMeta": {
+ "@opentelemetry/api": {
+ "optional": true
+ },
+ "@playwright/test": {
+ "optional": true
+ },
+ "babel-plugin-react-compiler": {
+ "optional": true
+ },
+ "sass": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/node-exports-info": {
+ "version": "1.6.0",
+ "resolved": "https://registry.npmjs.org/node-exports-info/-/node-exports-info-1.6.0.tgz",
+ "integrity": "sha512-pyFS63ptit/P5WqUkt+UUfe+4oevH+bFeIiPPdfb0pFeYEu/1ELnJu5l+5EcTKYL5M7zaAa7S8ddywgXypqKCw==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "array.prototype.flatmap": "^1.3.3",
+ "es-errors": "^1.3.0",
+ "object.entries": "^1.1.9",
+ "semver": "^6.3.1"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/node-releases": {
+ "version": "2.0.44",
+ "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.44.tgz",
+ "integrity": "sha512-5WUyunoPMsvvEhS8AxHtRzP+oA8UCkJ7YRxatWKjngndhDGLiqEVAQKWjFAiAiuL8zMRGzGSJxFnLetoa43qGQ==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/object-assign": {
+ "version": "4.1.1",
+ "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz",
+ "integrity": "sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/object-inspect": {
+ "version": "1.13.4",
+ "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.13.4.tgz",
+ "integrity": "sha512-W67iLl4J2EXEGTbfeHCffrjDfitvLANg0UlX3wFUUSTx92KXRFegMHUVgSqE+wvhAbi4WqjGg9czysTV2Epbew==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/object-keys": {
+ "version": "1.1.1",
+ "resolved": "https://registry.npmjs.org/object-keys/-/object-keys-1.1.1.tgz",
+ "integrity": "sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">= 0.4"
+ }
+ },
+ "node_modules/object.assign": {
+ "version": "4.1.7",
+ "resolved": "https://registry.npmjs.org/object.assign/-/object.assign-4.1.7.tgz",
+ "integrity": "sha512-nK28WOo+QIjBkDduTINE4JkF/UJJKyf2EJxvJKfblDpyg0Q+pkOHNTL0Qwy6NP6FhE/EnzV73BxxqcJaXY9anw==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "call-bind": "^1.0.8",
+ "call-bound": "^1.0.3",
+ "define-properties": "^1.2.1",
+ "es-object-atoms": "^1.0.0",
+ "has-symbols": "^1.1.0",
+ "object-keys": "^1.1.1"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/object.entries": {
+ "version": "1.1.9",
+ "resolved": "https://registry.npmjs.org/object.entries/-/object.entries-1.1.9.tgz",
+ "integrity": "sha512-8u/hfXFRBD1O0hPUjioLhoWFHRmt6tKA4/vZPyckBr18l1KE9uHrFaFaUi8MDRTpi4uak2goyPTSNJLXX2k2Hw==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "call-bind": "^1.0.8",
+ "call-bound": "^1.0.4",
+ "define-properties": "^1.2.1",
+ "es-object-atoms": "^1.1.1"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ }
+ },
+ "node_modules/object.fromentries": {
+ "version": "2.0.8",
+ "resolved": "https://registry.npmjs.org/object.fromentries/-/object.fromentries-2.0.8.tgz",
+ "integrity": "sha512-k6E21FzySsSK5a21KRADBd/NGneRegFO5pLHfdQLpRDETUNJueLXs3WCzyQ3tFRDYgbq3KHGXfTbi2bs8WQ6rQ==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "call-bind": "^1.0.7",
+ "define-properties": "^1.2.1",
+ "es-abstract": "^1.23.2",
+ "es-object-atoms": "^1.0.0"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/object.groupby": {
+ "version": "1.0.3",
+ "resolved": "https://registry.npmjs.org/object.groupby/-/object.groupby-1.0.3.tgz",
+ "integrity": "sha512-+Lhy3TQTuzXI5hevh8sBGqbmurHbbIjAi0Z4S63nthVLmLxfbj4T54a4CfZrXIrt9iP4mVAPYMo/v99taj3wjQ==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "call-bind": "^1.0.7",
+ "define-properties": "^1.2.1",
+ "es-abstract": "^1.23.2"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ }
+ },
+ "node_modules/object.values": {
+ "version": "1.2.1",
+ "resolved": "https://registry.npmjs.org/object.values/-/object.values-1.2.1.tgz",
+ "integrity": "sha512-gXah6aZrcUxjWg2zR2MwouP2eHlCBzdV4pygudehaKXSGW4v2AsRQUK+lwwXhii6KFZcunEnmSUoYp5CXibxtA==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "call-bind": "^1.0.8",
+ "call-bound": "^1.0.3",
+ "define-properties": "^1.2.1",
+ "es-object-atoms": "^1.0.0"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/optionator": {
+ "version": "0.9.4",
+ "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.4.tgz",
+ "integrity": "sha512-6IpQ7mKUxRcZNLIObR0hz7lxsapSSIYNZJwXPGeF0mTVqGKFIXj1DQcMoT22S3ROcLyY/rz0PWaWZ9ayWmad9g==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "deep-is": "^0.1.3",
+ "fast-levenshtein": "^2.0.6",
+ "levn": "^0.4.1",
+ "prelude-ls": "^1.2.1",
+ "type-check": "^0.4.0",
+ "word-wrap": "^1.2.5"
+ },
+ "engines": {
+ "node": ">= 0.8.0"
+ }
+ },
+ "node_modules/own-keys": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/own-keys/-/own-keys-1.0.1.tgz",
+ "integrity": "sha512-qFOyK5PjiWZd+QQIh+1jhdb9LpxTF0qs7Pm8o5QHYZ0M3vKqSqzsZaEB6oWlxZ+q2sJBMI/Ktgd2N5ZwQoRHfg==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "get-intrinsic": "^1.2.6",
+ "object-keys": "^1.1.1",
+ "safe-push-apply": "^1.0.0"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/p-limit": {
+ "version": "3.1.0",
+ "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz",
+ "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "yocto-queue": "^0.1.0"
+ },
+ "engines": {
+ "node": ">=10"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/p-locate": {
+ "version": "5.0.0",
+ "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-5.0.0.tgz",
+ "integrity": "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "p-limit": "^3.0.2"
+ },
+ "engines": {
+ "node": ">=10"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/pako": {
+ "version": "0.2.9",
+ "resolved": "https://registry.npmjs.org/pako/-/pako-0.2.9.tgz",
+ "integrity": "sha512-NUcwaKxUxWrZLpDG+z/xZaCgQITkA/Dv4V/T6bw7VON6l1Xz/VnrBqrYjZQ12TamKHzITTfOEIYUj48y2KXImA==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/parent-module": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz",
+ "integrity": "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "callsites": "^3.0.0"
+ },
+ "engines": {
+ "node": ">=6"
+ }
+ },
+ "node_modules/parse-css-color": {
+ "version": "0.2.1",
+ "resolved": "https://registry.npmjs.org/parse-css-color/-/parse-css-color-0.2.1.tgz",
+ "integrity": "sha512-bwS/GGIFV3b6KS4uwpzCFj4w297Yl3uqnSgIPsoQkx7GMLROXfMnWvxfNkL0oh8HVhZA4hvJoEoEIqonfJ3BWg==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "color-name": "^1.1.4",
+ "hex-rgb": "^4.1.0"
+ }
+ },
+ "node_modules/path-exists": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz",
+ "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/path-key": {
+ "version": "3.1.1",
+ "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz",
+ "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/path-parse": {
+ "version": "1.0.7",
+ "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz",
+ "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/path-to-regexp": {
+ "version": "6.3.0",
+ "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-6.3.0.tgz",
+ "integrity": "sha512-Yhpw4T9C6hPpgPeA28us07OJeqZ5EzQTkbfwuhsUg0c237RomFoETJgmp2sa3F/41gfLE6G5cqcYwznmeEeOlQ==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/pathe": {
+ "version": "2.0.3",
+ "resolved": "https://registry.npmjs.org/pathe/-/pathe-2.0.3.tgz",
+ "integrity": "sha512-WUjGcAqP1gQacoQe+OBJsFA7Ld4DyXuUIjZ5cc75cLHvJ7dtNsTugphxIADwspS+AraAUePCKrSVtPLFj/F88w==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/picocolors": {
+ "version": "1.1.1",
+ "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz",
+ "integrity": "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==",
+ "license": "ISC"
+ },
+ "node_modules/picomatch": {
+ "version": "2.3.2",
+ "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.2.tgz",
+ "integrity": "sha512-V7+vQEJ06Z+c5tSye8S+nHUfI51xoXIXjHQ99cQtKUkQqqO1kO/KCJUfZXuB47h/YBlDhah2H3hdUGXn8ie0oA==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=8.6"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/jonschlinkert"
+ }
+ },
+ "node_modules/possible-typed-array-names": {
+ "version": "1.1.0",
+ "resolved": "https://registry.npmjs.org/possible-typed-array-names/-/possible-typed-array-names-1.1.0.tgz",
+ "integrity": "sha512-/+5VFTchJDoVj3bhoqi6UeymcD00DAwb1nJwamzPvHEszJ4FpF6SNNbUbOS8yI56qHzdV8eK0qEfOSiodkTdxg==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">= 0.4"
+ }
+ },
+ "node_modules/postcss": {
+ "version": "8.5.25",
+ "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.25.tgz",
+ "integrity": "sha512-DTPx3RWSSnWyzLxQnlH0rJP+EW5ekl16ZU4/psbIhA0e53kJfdgaN5vKM+xP7yJtXVu+nfdVFmlgFDEKAe4Pyw==",
+ "funding": [
+ {
+ "type": "opencollective",
+ "url": "https://opencollective.com/postcss/"
+ },
+ {
+ "type": "tidelift",
+ "url": "https://tidelift.com/funding/github/npm/postcss"
+ },
+ {
+ "type": "github",
+ "url": "https://github.com/sponsors/ai"
+ }
+ ],
+ "license": "MIT",
+ "dependencies": {
+ "nanoid": "^3.3.16",
+ "picocolors": "^1.1.1",
+ "source-map-js": "^1.2.1"
+ },
+ "engines": {
+ "node": "^10 || ^12 || >=14"
+ }
+ },
+ "node_modules/postcss-value-parser": {
+ "version": "4.2.0",
+ "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-4.2.0.tgz",
+ "integrity": "sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/prelude-ls": {
+ "version": "1.2.1",
+ "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz",
+ "integrity": "sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">= 0.8.0"
+ }
+ },
+ "node_modules/prop-types": {
+ "version": "15.8.1",
+ "resolved": "https://registry.npmjs.org/prop-types/-/prop-types-15.8.1.tgz",
+ "integrity": "sha512-oj87CgZICdulUohogVAR7AjlC0327U4el4L6eAvOqCeudMDVU0NThNaV+b9Df4dXgSP1gXMTnPdhfe/2qDH5cg==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "loose-envify": "^1.4.0",
+ "object-assign": "^4.1.1",
+ "react-is": "^16.13.1"
+ }
+ },
+ "node_modules/punycode": {
+ "version": "2.3.1",
+ "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz",
+ "integrity": "sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=6"
+ }
+ },
+ "node_modules/queue-microtask": {
+ "version": "1.2.3",
+ "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz",
+ "integrity": "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==",
+ "dev": true,
+ "funding": [
+ {
+ "type": "github",
+ "url": "https://github.com/sponsors/feross"
+ },
+ {
+ "type": "patreon",
+ "url": "https://www.patreon.com/feross"
+ },
+ {
+ "type": "consulting",
+ "url": "https://feross.org/support"
+ }
+ ],
+ "license": "MIT"
+ },
+ "node_modules/react": {
+ "version": "19.2.6",
+ "resolved": "https://registry.npmjs.org/react/-/react-19.2.6.tgz",
+ "integrity": "sha512-sfWGGfavi0xr8Pg0sVsyHMAOziVYKgPLNrS7ig+ivMNb3wbCBw3KxtflsGBAwD3gYQlE/AEZsTLgToRrSCjb0Q==",
+ "license": "MIT",
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/react-dom": {
+ "version": "19.2.6",
+ "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-19.2.6.tgz",
+ "integrity": "sha512-0prMI+hvBbPjsWnxDLxlCGyM8PN6UuWjEUCYmZhO67xIV9Xasa/r/vDnq+Xyq4Lo27g8QSbO5YzARu0D1Sps3g==",
+ "license": "MIT",
+ "dependencies": {
+ "scheduler": "^0.27.0"
+ },
+ "peerDependencies": {
+ "react": "^19.2.6"
+ }
+ },
+ "node_modules/react-is": {
+ "version": "16.13.1",
+ "resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz",
+ "integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/react-server-dom-webpack": {
+ "version": "19.2.6",
+ "resolved": "https://registry.npmjs.org/react-server-dom-webpack/-/react-server-dom-webpack-19.2.6.tgz",
+ "integrity": "sha512-762YXjBPc6hw2V16k4x1sdnw0mxghcSPzoiOhefGYjiTguJLCImGBUz6EjznPIfqKhWgLtpaQMlBhp66N8dKrw==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "acorn-loose": "^8.3.0",
+ "neo-async": "^2.6.1",
+ "webpack-sources": "^3.2.0"
+ },
+ "engines": {
+ "node": ">=0.10.0"
+ },
+ "peerDependencies": {
+ "react": "^19.2.6",
+ "react-dom": "^19.2.6",
+ "webpack": "^5.59.0"
+ }
+ },
+ "node_modules/reflect.getprototypeof": {
+ "version": "1.0.10",
+ "resolved": "https://registry.npmjs.org/reflect.getprototypeof/-/reflect.getprototypeof-1.0.10.tgz",
+ "integrity": "sha512-00o4I+DVrefhv+nX0ulyi3biSHCPDe+yLv5o/p6d/UVlirijB8E16FtfwSAi4g3tcqrQ4lRAqQSoFEZJehYEcw==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "call-bind": "^1.0.8",
+ "define-properties": "^1.2.1",
+ "es-abstract": "^1.23.9",
+ "es-errors": "^1.3.0",
+ "es-object-atoms": "^1.0.0",
+ "get-intrinsic": "^1.2.7",
+ "get-proto": "^1.0.1",
+ "which-builtin-type": "^1.2.1"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/regexp.prototype.flags": {
+ "version": "1.5.4",
+ "resolved": "https://registry.npmjs.org/regexp.prototype.flags/-/regexp.prototype.flags-1.5.4.tgz",
+ "integrity": "sha512-dYqgNSZbDwkaJ2ceRd9ojCGjBq+mOm9LmtXnAnEGyHhN/5R7iDW2TRw3h+o/jCFxus3P2LfWIIiwowAjANm7IA==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "call-bind": "^1.0.8",
+ "define-properties": "^1.2.1",
+ "es-errors": "^1.3.0",
+ "get-proto": "^1.0.1",
+ "gopd": "^1.2.0",
+ "set-function-name": "^2.0.2"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/require-from-string": {
+ "version": "2.0.2",
+ "resolved": "https://registry.npmjs.org/require-from-string/-/require-from-string-2.0.2.tgz",
+ "integrity": "sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==",
+ "dev": true,
+ "license": "MIT",
+ "peer": true,
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/resolve": {
+ "version": "2.0.0-next.7",
+ "resolved": "https://registry.npmjs.org/resolve/-/resolve-2.0.0-next.7.tgz",
+ "integrity": "sha512-tqt+NBWwyaMgw3zDsnygx4CByWjQEJHOPMdslYhppaQSJUtL/D4JO9CcBBlhPoI8lz9oJIDXkwXfhF4aWqP8xQ==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "es-errors": "^1.3.0",
+ "is-core-module": "^2.16.2",
+ "node-exports-info": "^1.6.0",
+ "object-keys": "^1.1.1",
+ "path-parse": "^1.0.7",
+ "supports-preserve-symlinks-flag": "^1.0.0"
+ },
+ "bin": {
+ "resolve": "bin/resolve"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/resolve-from": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz",
+ "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=4"
+ }
+ },
+ "node_modules/resolve-pkg-maps": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/resolve-pkg-maps/-/resolve-pkg-maps-1.0.0.tgz",
+ "integrity": "sha512-seS2Tj26TBVOC2NIc2rOe2y2ZO7efxITtLZcGSOnHHNOQ7CkiUBfw0Iw2ck6xkIhPwLhKNLS8BO+hEpngQlqzw==",
+ "dev": true,
+ "license": "MIT",
+ "funding": {
+ "url": "https://github.com/privatenumber/resolve-pkg-maps?sponsor=1"
+ }
+ },
+ "node_modules/reusify": {
+ "version": "1.1.0",
+ "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.1.0.tgz",
+ "integrity": "sha512-g6QUff04oZpHs0eG5p83rFLhHeV00ug/Yf9nZM6fLeUrPguBTkTQOdpAWWspMh55TZfVQDPaN3NQJfbVRAxdIw==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "iojs": ">=1.0.0",
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/rolldown": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/rolldown/-/rolldown-1.0.1.tgz",
+ "integrity": "sha512-X0KQHljNnEkWNqqiz9zJrGunh1B0HgOxLXvnFpCOcadzcy5qohZ3tqMEUg00vncoRovXuK3ZqCT9KnnKzoInFQ==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@oxc-project/types": "=0.130.0",
+ "@rolldown/pluginutils": "^1.0.0"
+ },
+ "bin": {
+ "rolldown": "bin/cli.mjs"
+ },
+ "engines": {
+ "node": "^20.19.0 || >=22.12.0"
+ },
+ "optionalDependencies": {
+ "@rolldown/binding-android-arm64": "1.0.1",
+ "@rolldown/binding-darwin-arm64": "1.0.1",
+ "@rolldown/binding-darwin-x64": "1.0.1",
+ "@rolldown/binding-freebsd-x64": "1.0.1",
+ "@rolldown/binding-linux-arm-gnueabihf": "1.0.1",
+ "@rolldown/binding-linux-arm64-gnu": "1.0.1",
+ "@rolldown/binding-linux-arm64-musl": "1.0.1",
+ "@rolldown/binding-linux-ppc64-gnu": "1.0.1",
+ "@rolldown/binding-linux-s390x-gnu": "1.0.1",
+ "@rolldown/binding-linux-x64-gnu": "1.0.1",
+ "@rolldown/binding-linux-x64-musl": "1.0.1",
+ "@rolldown/binding-openharmony-arm64": "1.0.1",
+ "@rolldown/binding-wasm32-wasi": "1.0.1",
+ "@rolldown/binding-win32-arm64-msvc": "1.0.1",
+ "@rolldown/binding-win32-x64-msvc": "1.0.1"
+ }
+ },
+ "node_modules/run-parallel": {
+ "version": "1.2.0",
+ "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz",
+ "integrity": "sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==",
+ "dev": true,
+ "funding": [
+ {
+ "type": "github",
+ "url": "https://github.com/sponsors/feross"
+ },
+ {
+ "type": "patreon",
+ "url": "https://www.patreon.com/feross"
+ },
+ {
+ "type": "consulting",
+ "url": "https://feross.org/support"
+ }
+ ],
+ "license": "MIT",
+ "dependencies": {
+ "queue-microtask": "^1.2.2"
+ }
+ },
+ "node_modules/safe-array-concat": {
+ "version": "1.1.4",
+ "resolved": "https://registry.npmjs.org/safe-array-concat/-/safe-array-concat-1.1.4.tgz",
+ "integrity": "sha512-wtZlHyOje6OZTGqAoaDKxFkgRtkF9CnHAVnCHKfuj200wAgL+bSJhdsCD2l0Qx/2ekEXjPWcyKkfGb5CPboslg==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "call-bind": "^1.0.9",
+ "call-bound": "^1.0.4",
+ "get-intrinsic": "^1.3.0",
+ "has-symbols": "^1.1.0",
+ "isarray": "^2.0.5"
+ },
+ "engines": {
+ "node": ">=0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/safe-push-apply": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/safe-push-apply/-/safe-push-apply-1.0.0.tgz",
+ "integrity": "sha512-iKE9w/Z7xCzUMIZqdBsp6pEQvwuEebH4vdpjcDWnyzaI6yl6O9FHvVpmGelvEHNsoY6wGblkxR6Zty/h00WiSA==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "es-errors": "^1.3.0",
+ "isarray": "^2.0.5"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/safe-regex-test": {
+ "version": "1.1.0",
+ "resolved": "https://registry.npmjs.org/safe-regex-test/-/safe-regex-test-1.1.0.tgz",
+ "integrity": "sha512-x/+Cz4YrimQxQccJf5mKEbIa1NzeCRNI5Ecl/ekmlYaampdNLPalVyIcCZNNH3MvmqBugV5TMYZXv0ljslUlaw==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "call-bound": "^1.0.2",
+ "es-errors": "^1.3.0",
+ "is-regex": "^1.2.1"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/satori": {
+ "version": "0.16.0",
+ "resolved": "https://registry.npmjs.org/satori/-/satori-0.16.0.tgz",
+ "integrity": "sha512-ZvHN3ygzZ8FuxjSNB+mKBiF/NIoqHzlBGbD0MJiT+MvSsFOvotnWOhdTjxKzhHRT2wPC1QbhLzx2q/Y83VhfYQ==",
+ "dev": true,
+ "license": "MPL-2.0",
+ "dependencies": {
+ "@shuding/opentype.js": "1.4.0-beta.0",
+ "css-background-parser": "^0.1.0",
+ "css-box-shadow": "1.0.0-3",
+ "css-gradient-parser": "^0.0.16",
+ "css-to-react-native": "^3.0.0",
+ "emoji-regex-xs": "^2.0.1",
+ "escape-html": "^1.0.3",
+ "linebreak": "^1.1.0",
+ "parse-css-color": "^0.2.1",
+ "postcss-value-parser": "^4.2.0",
+ "yoga-layout": "^3.2.1"
+ },
+ "engines": {
+ "node": ">=16"
+ }
+ },
+ "node_modules/scheduler": {
+ "version": "0.27.0",
+ "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.27.0.tgz",
+ "integrity": "sha512-eNv+WrVbKu1f3vbYJT/xtiF5syA5HPIMtf9IgY/nKg0sWqzAUEvqY/xm7OcZc/qafLx/iO9FgOmeSAp4v5ti/Q==",
+ "license": "MIT"
+ },
+ "node_modules/schema-utils": {
+ "version": "4.3.3",
+ "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-4.3.3.tgz",
+ "integrity": "sha512-eflK8wEtyOE6+hsaRVPxvUKYCpRgzLqDTb8krvAsRIwOGlHoSgYLgBXoubGgLd2fT41/OUYdb48v4k4WWHQurA==",
+ "dev": true,
+ "license": "MIT",
+ "peer": true,
+ "dependencies": {
+ "@types/json-schema": "^7.0.9",
+ "ajv": "^8.9.0",
+ "ajv-formats": "^2.1.1",
+ "ajv-keywords": "^5.1.0"
+ },
+ "engines": {
+ "node": ">= 10.13.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/webpack"
+ }
+ },
+ "node_modules/schema-utils/node_modules/ajv": {
+ "version": "8.20.0",
+ "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.20.0.tgz",
+ "integrity": "sha512-Thbli+OlOj+iMPYFBVBfJ3OmCAnaSyNn4M1vz9T6Gka5Jt9ba/HIR56joy65tY6kx/FCF5VXNB819Y7/GUrBGA==",
+ "dev": true,
+ "license": "MIT",
+ "peer": true,
+ "dependencies": {
+ "fast-deep-equal": "^3.1.3",
+ "fast-uri": "^3.0.1",
+ "json-schema-traverse": "^1.0.0",
+ "require-from-string": "^2.0.2"
+ },
+ "funding": {
+ "type": "github",
+ "url": "https://github.com/sponsors/epoberezkin"
+ }
+ },
+ "node_modules/schema-utils/node_modules/ajv-keywords": {
+ "version": "5.1.0",
+ "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-5.1.0.tgz",
+ "integrity": "sha512-YCS/JNFAUyr5vAuhk1DWm1CBxRHW9LbJ2ozWeemrIqpbsqKjHVxYPyi5GC0rjZIT5JxJ3virVTS8wk4i/Z+krw==",
+ "dev": true,
+ "license": "MIT",
+ "peer": true,
+ "dependencies": {
+ "fast-deep-equal": "^3.1.3"
+ },
+ "peerDependencies": {
+ "ajv": "^8.8.2"
+ }
+ },
+ "node_modules/schema-utils/node_modules/json-schema-traverse": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz",
+ "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==",
+ "dev": true,
+ "license": "MIT",
+ "peer": true
+ },
+ "node_modules/semver": {
+ "version": "6.3.1",
+ "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz",
+ "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==",
+ "dev": true,
+ "license": "ISC",
+ "bin": {
+ "semver": "bin/semver.js"
+ }
+ },
+ "node_modules/set-function-length": {
+ "version": "1.2.2",
+ "resolved": "https://registry.npmjs.org/set-function-length/-/set-function-length-1.2.2.tgz",
+ "integrity": "sha512-pgRc4hJ4/sNjWCSS9AmnS40x3bNMDTknHgL5UaMBTMyJnU90EgWh1Rz+MC9eFu4BuN/UwZjKQuY/1v3rM7HMfg==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "define-data-property": "^1.1.4",
+ "es-errors": "^1.3.0",
+ "function-bind": "^1.1.2",
+ "get-intrinsic": "^1.2.4",
+ "gopd": "^1.0.1",
+ "has-property-descriptors": "^1.0.2"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ }
+ },
+ "node_modules/set-function-name": {
+ "version": "2.0.2",
+ "resolved": "https://registry.npmjs.org/set-function-name/-/set-function-name-2.0.2.tgz",
+ "integrity": "sha512-7PGFlmtwsEADb0WYyvCMa1t+yke6daIG4Wirafur5kcf+MhUnPms1UeR0CKQdTZD81yESwMHbtn+TR+dMviakQ==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "define-data-property": "^1.1.4",
+ "es-errors": "^1.3.0",
+ "functions-have-names": "^1.2.3",
+ "has-property-descriptors": "^1.0.2"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ }
+ },
+ "node_modules/set-proto": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/set-proto/-/set-proto-1.0.0.tgz",
+ "integrity": "sha512-RJRdvCo6IAnPdsvP/7m6bsQqNnn1FCBX5ZNtFL98MmFF/4xAIJTIg1YbHW5DC2W5SKZanrC6i4HsJqlajw/dZw==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "dunder-proto": "^1.0.1",
+ "es-errors": "^1.3.0",
+ "es-object-atoms": "^1.0.0"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ }
+ },
+ "node_modules/sharp": {
+ "version": "0.35.3",
+ "resolved": "https://registry.npmjs.org/sharp/-/sharp-0.35.3.tgz",
+ "integrity": "sha512-ej0zVHuZGHCiABXcNxeYhpRnPNPAcvbG8RMdBAhDAxLKkCRVSpK3Iyu7qbqw3JMzoj0REeM6f3tJLtVwl0023Q==",
+ "devOptional": true,
+ "license": "Apache-2.0",
+ "dependencies": {
+ "@img/colour": "^1.1.0",
+ "detect-libc": "^2.1.2",
+ "semver": "^7.8.5"
+ },
+ "engines": {
+ "node": ">=20.9.0"
+ },
+ "funding": {
+ "url": "https://opencollective.com/libvips"
+ },
+ "optionalDependencies": {
+ "@img/sharp-darwin-arm64": "0.35.3",
+ "@img/sharp-darwin-x64": "0.35.3",
+ "@img/sharp-freebsd-wasm32": "0.35.3",
+ "@img/sharp-libvips-darwin-arm64": "1.3.2",
+ "@img/sharp-libvips-darwin-x64": "1.3.2",
+ "@img/sharp-libvips-linux-arm": "1.3.2",
+ "@img/sharp-libvips-linux-arm64": "1.3.2",
+ "@img/sharp-libvips-linux-ppc64": "1.3.2",
+ "@img/sharp-libvips-linux-riscv64": "1.3.2",
+ "@img/sharp-libvips-linux-s390x": "1.3.2",
+ "@img/sharp-libvips-linux-x64": "1.3.2",
+ "@img/sharp-libvips-linuxmusl-arm64": "1.3.2",
+ "@img/sharp-libvips-linuxmusl-x64": "1.3.2",
+ "@img/sharp-linux-arm": "0.35.3",
+ "@img/sharp-linux-arm64": "0.35.3",
+ "@img/sharp-linux-ppc64": "0.35.3",
+ "@img/sharp-linux-riscv64": "0.35.3",
+ "@img/sharp-linux-s390x": "0.35.3",
+ "@img/sharp-linux-x64": "0.35.3",
+ "@img/sharp-linuxmusl-arm64": "0.35.3",
+ "@img/sharp-linuxmusl-x64": "0.35.3",
+ "@img/sharp-webcontainers-wasm32": "0.35.3",
+ "@img/sharp-win32-arm64": "0.35.3",
+ "@img/sharp-win32-ia32": "0.35.3",
+ "@img/sharp-win32-x64": "0.35.3"
+ },
+ "peerDependenciesMeta": {
+ "@types/node": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/sharp/node_modules/semver": {
+ "version": "7.8.5",
+ "resolved": "https://registry.npmjs.org/semver/-/semver-7.8.5.tgz",
+ "integrity": "sha512-Y7/KDsb8LjooZpwaqGyulO6DQlksgCncchHGk+sZIY4SBvUocMBEFH5Ur1fI4dV+Jvl0w6cjvucaIi40puRioA==",
+ "devOptional": true,
+ "license": "ISC",
+ "bin": {
+ "semver": "bin/semver.js"
+ },
+ "engines": {
+ "node": ">=10"
+ }
+ },
+ "node_modules/shebang-command": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz",
+ "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "shebang-regex": "^3.0.0"
+ },
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/shebang-regex": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz",
+ "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/side-channel": {
+ "version": "1.1.0",
+ "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.1.0.tgz",
+ "integrity": "sha512-ZX99e6tRweoUXqR+VBrslhda51Nh5MTQwou5tnUDgbtyM0dBgmhEDtWGP/xbKn6hqfPRHujUNwz5fy/wbbhnpw==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "es-errors": "^1.3.0",
+ "object-inspect": "^1.13.3",
+ "side-channel-list": "^1.0.0",
+ "side-channel-map": "^1.0.1",
+ "side-channel-weakmap": "^1.0.2"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/side-channel-list": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/side-channel-list/-/side-channel-list-1.0.1.tgz",
+ "integrity": "sha512-mjn/0bi/oUURjc5Xl7IaWi/OJJJumuoJFQJfDDyO46+hBWsfaVM65TBHq2eoZBhzl9EchxOijpkbRC8SVBQU0w==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "es-errors": "^1.3.0",
+ "object-inspect": "^1.13.4"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/side-channel-map": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/side-channel-map/-/side-channel-map-1.0.1.tgz",
+ "integrity": "sha512-VCjCNfgMsby3tTdo02nbjtM/ewra6jPHmpThenkTYh8pG9ucZ/1P8So4u4FGBek/BjpOVsDCMoLA/iuBKIFXRA==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "call-bound": "^1.0.2",
+ "es-errors": "^1.3.0",
+ "get-intrinsic": "^1.2.5",
+ "object-inspect": "^1.13.3"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/side-channel-weakmap": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/side-channel-weakmap/-/side-channel-weakmap-1.0.2.tgz",
+ "integrity": "sha512-WPS/HvHQTYnHisLo9McqBHOJk2FkHO/tlpvldyrnem4aeQp4hai3gythswg6p01oSoTl58rcpiFAjF2br2Ak2A==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "call-bound": "^1.0.2",
+ "es-errors": "^1.3.0",
+ "get-intrinsic": "^1.2.5",
+ "object-inspect": "^1.13.3",
+ "side-channel-map": "^1.0.1"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/source-map": {
+ "version": "0.6.1",
+ "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz",
+ "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==",
+ "dev": true,
+ "license": "BSD-3-Clause",
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/source-map-js": {
+ "version": "1.2.1",
+ "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.1.tgz",
+ "integrity": "sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==",
+ "license": "BSD-3-Clause",
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/source-map-support": {
+ "version": "0.5.21",
+ "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.21.tgz",
+ "integrity": "sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "buffer-from": "^1.0.0",
+ "source-map": "^0.6.0"
+ }
+ },
+ "node_modules/srvx": {
+ "version": "0.11.15",
+ "resolved": "https://registry.npmjs.org/srvx/-/srvx-0.11.15.tgz",
+ "integrity": "sha512-iXsux0UcOjdvs0LCMa2Ws3WwcDUozA3JN3BquNXkaFPP7TpRqgunKdEgoZ/uwb1J6xaYHfxtz9Twlh6yzwM6Tg==",
+ "dev": true,
+ "license": "MIT",
+ "bin": {
+ "srvx": "bin/srvx.mjs"
+ },
+ "engines": {
+ "node": ">=20.16.0"
+ }
+ },
+ "node_modules/stable-hash": {
+ "version": "0.0.5",
+ "resolved": "https://registry.npmjs.org/stable-hash/-/stable-hash-0.0.5.tgz",
+ "integrity": "sha512-+L3ccpzibovGXFK+Ap/f8LOS0ahMrHTf3xu7mMLSpEGU0EO9ucaysSylKo9eRDFNhWve/y275iPmIZ4z39a9iA==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/stop-iteration-iterator": {
+ "version": "1.1.0",
+ "resolved": "https://registry.npmjs.org/stop-iteration-iterator/-/stop-iteration-iterator-1.1.0.tgz",
+ "integrity": "sha512-eLoXW/DHyl62zxY4SCaIgnRhuMr6ri4juEYARS8E6sCEqzKpOiE521Ucofdx+KnDZl5xmvGYaaKCk5FEOxJCoQ==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "es-errors": "^1.3.0",
+ "internal-slot": "^1.1.0"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ }
+ },
+ "node_modules/string.prototype.codepointat": {
+ "version": "0.2.1",
+ "resolved": "https://registry.npmjs.org/string.prototype.codepointat/-/string.prototype.codepointat-0.2.1.tgz",
+ "integrity": "sha512-2cBVCj6I4IOvEnjgO/hWqXjqBGsY+zwPmHl12Srk9IXSZ56Jwwmy+66XO5Iut/oQVR7t5ihYdLB0GMa4alEUcg==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/string.prototype.includes": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/string.prototype.includes/-/string.prototype.includes-2.0.1.tgz",
+ "integrity": "sha512-o7+c9bW6zpAdJHTtujeePODAhkuicdAryFsfVKwA+wGw89wJ4GTY484WTucM9hLtDEOpOvI+aHnzqnC5lHp4Rg==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "call-bind": "^1.0.7",
+ "define-properties": "^1.2.1",
+ "es-abstract": "^1.23.3"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ }
+ },
+ "node_modules/string.prototype.matchall": {
+ "version": "4.0.12",
+ "resolved": "https://registry.npmjs.org/string.prototype.matchall/-/string.prototype.matchall-4.0.12.tgz",
+ "integrity": "sha512-6CC9uyBL+/48dYizRf7H7VAYCMCNTBeM78x/VTUe9bFEaxBepPJDa1Ow99LqI/1yF7kuy7Q3cQsYMrcjGUcskA==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "call-bind": "^1.0.8",
+ "call-bound": "^1.0.3",
+ "define-properties": "^1.2.1",
+ "es-abstract": "^1.23.6",
+ "es-errors": "^1.3.0",
+ "es-object-atoms": "^1.0.0",
+ "get-intrinsic": "^1.2.6",
+ "gopd": "^1.2.0",
+ "has-symbols": "^1.1.0",
+ "internal-slot": "^1.1.0",
+ "regexp.prototype.flags": "^1.5.3",
+ "set-function-name": "^2.0.2",
+ "side-channel": "^1.1.0"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/string.prototype.repeat": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/string.prototype.repeat/-/string.prototype.repeat-1.0.0.tgz",
+ "integrity": "sha512-0u/TldDbKD8bFCQ/4f5+mNRrXwZ8hg2w7ZR8wa16e8z9XpePWl3eGEcUD0OXpEH/VJH/2G3gjUtR3ZOiBe2S/w==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "define-properties": "^1.1.3",
+ "es-abstract": "^1.17.5"
+ }
+ },
+ "node_modules/string.prototype.trim": {
+ "version": "1.2.10",
+ "resolved": "https://registry.npmjs.org/string.prototype.trim/-/string.prototype.trim-1.2.10.tgz",
+ "integrity": "sha512-Rs66F0P/1kedk5lyYyH9uBzuiI/kNRmwJAR9quK6VOtIpZ2G+hMZd+HQbbv25MgCA6gEffoMZYxlTod4WcdrKA==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "call-bind": "^1.0.8",
+ "call-bound": "^1.0.2",
+ "define-data-property": "^1.1.4",
+ "define-properties": "^1.2.1",
+ "es-abstract": "^1.23.5",
+ "es-object-atoms": "^1.0.0",
+ "has-property-descriptors": "^1.0.2"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/string.prototype.trimend": {
+ "version": "1.0.9",
+ "resolved": "https://registry.npmjs.org/string.prototype.trimend/-/string.prototype.trimend-1.0.9.tgz",
+ "integrity": "sha512-G7Ok5C6E/j4SGfyLCloXTrngQIQU3PWtXGst3yM7Bea9FRURf1S42ZHlZZtsNque2FN2PoUhfZXYLNWwEr4dLQ==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "call-bind": "^1.0.8",
+ "call-bound": "^1.0.2",
+ "define-properties": "^1.2.1",
+ "es-object-atoms": "^1.0.0"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/string.prototype.trimstart": {
+ "version": "1.0.8",
+ "resolved": "https://registry.npmjs.org/string.prototype.trimstart/-/string.prototype.trimstart-1.0.8.tgz",
+ "integrity": "sha512-UXSH262CSZY1tfu3G3Secr6uGLCFVPMhIqHjlgCUtCCcgihYc/xKs9djMTMUOb2j1mVSeU8EU6NWc/iQKU6Gfg==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "call-bind": "^1.0.7",
+ "define-properties": "^1.2.1",
+ "es-object-atoms": "^1.0.0"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/strip-bom": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-3.0.0.tgz",
+ "integrity": "sha512-vavAMRXOgBVNF6nyEEmL3DBK19iRpDcoIwW+swQ+CbGiu7lju6t+JklA1MHweoWtadgt4ISVUsXLyDq34ddcwA==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=4"
+ }
+ },
+ "node_modules/strip-json-comments": {
+ "version": "3.1.1",
+ "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz",
+ "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=8"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/strip-literal": {
+ "version": "3.1.0",
+ "resolved": "https://registry.npmjs.org/strip-literal/-/strip-literal-3.1.0.tgz",
+ "integrity": "sha512-8r3mkIM/2+PpjHoOtiAW8Rg3jJLHaV7xPwG+YRGrv6FP0wwk/toTpATxWYOW0BKdWwl82VT2tFYi5DlROa0Mxg==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "js-tokens": "^9.0.1"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/antfu"
+ }
+ },
+ "node_modules/strip-literal/node_modules/js-tokens": {
+ "version": "9.0.1",
+ "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-9.0.1.tgz",
+ "integrity": "sha512-mxa9E9ITFOt0ban3j6L5MpjwegGz6lBQmM1IJkWeBZGcMxto50+eWdjC/52xDbS2vy0k7vIMK0Fe2wfL9OQSpQ==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/styled-jsx": {
+ "version": "5.1.6",
+ "resolved": "https://registry.npmjs.org/styled-jsx/-/styled-jsx-5.1.6.tgz",
+ "integrity": "sha512-qSVyDTeMotdvQYoHWLNGwRFJHC+i+ZvdBRYosOFgC+Wg1vx4frN2/RG/NA7SYqqvKNLf39P2LSRA2pu6n0XYZA==",
+ "license": "MIT",
+ "dependencies": {
+ "client-only": "0.0.1"
+ },
+ "engines": {
+ "node": ">= 12.0.0"
+ },
+ "peerDependencies": {
+ "react": ">= 16.8.0 || 17.x.x || ^18.0.0-0 || ^19.0.0-0"
+ },
+ "peerDependenciesMeta": {
+ "@babel/core": {
+ "optional": true
+ },
+ "babel-plugin-macros": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/supports-color": {
+ "version": "7.2.0",
+ "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz",
+ "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "has-flag": "^4.0.0"
+ },
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/supports-preserve-symlinks-flag": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz",
+ "integrity": "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/tailwindcss": {
+ "version": "4.2.1",
+ "resolved": "https://registry.npmjs.org/tailwindcss/-/tailwindcss-4.2.1.tgz",
+ "integrity": "sha512-/tBrSQ36vCleJkAOsy9kbNTgaxvGbyOamC30PRePTQe/o1MFwEKHQk4Cn7BNGaPtjp+PuUrByJehM1hgxfq4sw==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/tapable": {
+ "version": "2.3.3",
+ "resolved": "https://registry.npmjs.org/tapable/-/tapable-2.3.3.tgz",
+ "integrity": "sha512-uxc/zpqFg6x7C8vOE7lh6Lbda8eEL9zmVm/PLeTPBRhh1xCgdWaQ+J1CUieGpIfm2HdtsUpRv+HshiasBMcc6A==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=6"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/webpack"
+ }
+ },
+ "node_modules/terser": {
+ "version": "5.47.1",
+ "resolved": "https://registry.npmjs.org/terser/-/terser-5.47.1.tgz",
+ "integrity": "sha512-tPbLXTI6ohPASb/1YViL428oEHu6/qv1OxqYnfaonVCFHqx4+wCd95pHrQWsL5X4pl90CTyW9piSAsS2L0VoMw==",
+ "dev": true,
+ "license": "BSD-2-Clause",
+ "peer": true,
+ "dependencies": {
+ "@jridgewell/source-map": "^0.3.3",
+ "acorn": "^8.15.0",
+ "commander": "^2.20.0",
+ "source-map-support": "~0.5.20"
+ },
+ "bin": {
+ "terser": "bin/terser"
+ },
+ "engines": {
+ "node": ">=10"
+ }
+ },
+ "node_modules/terser-webpack-plugin": {
+ "version": "5.6.0",
+ "resolved": "https://registry.npmjs.org/terser-webpack-plugin/-/terser-webpack-plugin-5.6.0.tgz",
+ "integrity": "sha512-Eum+5ajkaOhf5KbM26osvv21kLD7BaGqQ1UA4Ami4arYwylmGUQTgHFpHDdmJod1q4QXa66p0to/FBKID+J1vA==",
+ "dev": true,
+ "license": "MIT",
+ "peer": true,
+ "dependencies": {
+ "@jridgewell/trace-mapping": "^0.3.25",
+ "jest-worker": "^27.4.5",
+ "schema-utils": "^4.3.0",
+ "terser": "^5.31.1"
+ },
+ "engines": {
+ "node": ">= 10.13.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/webpack"
+ },
+ "peerDependencies": {
+ "webpack": "^5.1.0"
+ },
+ "peerDependenciesMeta": {
+ "@minify-html/node": {
+ "optional": true
+ },
+ "@swc/core": {
+ "optional": true
+ },
+ "@swc/css": {
+ "optional": true
+ },
+ "@swc/html": {
+ "optional": true
+ },
+ "clean-css": {
+ "optional": true
+ },
+ "cssnano": {
+ "optional": true
+ },
+ "csso": {
+ "optional": true
+ },
+ "esbuild": {
+ "optional": true
+ },
+ "html-minifier-terser": {
+ "optional": true
+ },
+ "lightningcss": {
+ "optional": true
+ },
+ "postcss": {
+ "optional": true
+ },
+ "uglify-js": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/tiny-inflate": {
+ "version": "1.0.3",
+ "resolved": "https://registry.npmjs.org/tiny-inflate/-/tiny-inflate-1.0.3.tgz",
+ "integrity": "sha512-pkY1fj1cKHb2seWDy0B16HeWyczlJA9/WW3u3c4z/NiWDsO3DOU5D7nhTLE9CF0yXv/QZFY7sEJmj24dK+Rrqw==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/tinyglobby": {
+ "version": "0.2.16",
+ "resolved": "https://registry.npmjs.org/tinyglobby/-/tinyglobby-0.2.16.tgz",
+ "integrity": "sha512-pn99VhoACYR8nFHhxqix+uvsbXineAasWm5ojXoN8xEwK5Kd3/TrhNn1wByuD52UxWRLy8pu+kRMniEi6Eq9Zg==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "fdir": "^6.5.0",
+ "picomatch": "^4.0.4"
+ },
+ "engines": {
+ "node": ">=12.0.0"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/SuperchupuDev"
+ }
+ },
+ "node_modules/tinyglobby/node_modules/fdir": {
+ "version": "6.5.0",
+ "resolved": "https://registry.npmjs.org/fdir/-/fdir-6.5.0.tgz",
+ "integrity": "sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=12.0.0"
+ },
+ "peerDependencies": {
+ "picomatch": "^3 || ^4"
+ },
+ "peerDependenciesMeta": {
+ "picomatch": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/tinyglobby/node_modules/picomatch": {
+ "version": "4.0.4",
+ "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.4.tgz",
+ "integrity": "sha512-QP88BAKvMam/3NxH6vj2o21R6MjxZUAd6nlwAS/pnGvN9IVLocLHxGYIzFhg6fUQ+5th6P4dv4eW9jX3DSIj7A==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=12"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/jonschlinkert"
+ }
+ },
+ "node_modules/to-regex-range": {
+ "version": "5.0.1",
+ "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz",
+ "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "is-number": "^7.0.0"
+ },
+ "engines": {
+ "node": ">=8.0"
+ }
+ },
+ "node_modules/ts-api-utils": {
+ "version": "2.5.0",
+ "resolved": "https://registry.npmjs.org/ts-api-utils/-/ts-api-utils-2.5.0.tgz",
+ "integrity": "sha512-OJ/ibxhPlqrMM0UiNHJ/0CKQkoKF243/AEmplt3qpRgkW8VG7IfOS41h7V8TjITqdByHzrjcS/2si+y4lIh8NA==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=18.12"
+ },
+ "peerDependencies": {
+ "typescript": ">=4.8.4"
+ }
+ },
+ "node_modules/tsconfck": {
+ "version": "3.1.6",
+ "resolved": "https://registry.npmjs.org/tsconfck/-/tsconfck-3.1.6.tgz",
+ "integrity": "sha512-ks6Vjr/jEw0P1gmOVwutM3B7fWxoWBL2KRDb1JfqGVawBmO5UsvmWOQFGHBPl5yxYz4eERr19E6L7NMv+Fej4w==",
+ "dev": true,
+ "license": "MIT",
+ "bin": {
+ "tsconfck": "bin/tsconfck.js"
+ },
+ "engines": {
+ "node": "^18 || >=20"
+ },
+ "peerDependencies": {
+ "typescript": "^5.0.0"
+ },
+ "peerDependenciesMeta": {
+ "typescript": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/tsconfig-paths": {
+ "version": "3.15.0",
+ "resolved": "https://registry.npmjs.org/tsconfig-paths/-/tsconfig-paths-3.15.0.tgz",
+ "integrity": "sha512-2Ac2RgzDe/cn48GvOe3M+o82pEFewD3UPbyoUHHdKasHwJKjds4fLXWf/Ux5kATBKN20oaFGu+jbElp1pos0mg==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@types/json5": "^0.0.29",
+ "json5": "^1.0.2",
+ "minimist": "^1.2.6",
+ "strip-bom": "^3.0.0"
+ }
+ },
+ "node_modules/tsconfig-paths/node_modules/json5": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/json5/-/json5-1.0.2.tgz",
+ "integrity": "sha512-g1MWMLBiz8FKi1e4w0UyVL3w+iJceWAFBAaBnnGKOpNa5f8TLktkbre1+s6oICydWAm+HRUGTmI+//xv2hvXYA==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "minimist": "^1.2.0"
+ },
+ "bin": {
+ "json5": "lib/cli.js"
+ }
+ },
+ "node_modules/tslib": {
+ "version": "2.8.1",
+ "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz",
+ "integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==",
+ "license": "0BSD"
+ },
+ "node_modules/tsx": {
+ "version": "4.22.1",
+ "resolved": "https://registry.npmjs.org/tsx/-/tsx-4.22.1.tgz",
+ "integrity": "sha512-TvncJykhxAzFCk0VQZKBTClall4Pm7qXDSodb6uxi8QFa8X8mT6ABjxxsQ2opDRYxG7AzcRWXaFtruz5HJKuWg==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "esbuild": "~0.28.0"
+ },
+ "bin": {
+ "tsx": "dist/cli.mjs"
+ },
+ "engines": {
+ "node": ">=18.0.0"
+ },
+ "optionalDependencies": {
+ "fsevents": "~2.3.3"
+ }
+ },
+ "node_modules/turbo-stream": {
+ "version": "3.2.0",
+ "resolved": "https://registry.npmjs.org/turbo-stream/-/turbo-stream-3.2.0.tgz",
+ "integrity": "sha512-EK+bZ9UVrVh7JLslVFOV0GEMsociOqVOvEMTAd4ixMyffN5YNIEdLZWXUx5PJqDbTxSIBWw04HS9gCY4frYQDQ==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/type-check": {
+ "version": "0.4.0",
+ "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz",
+ "integrity": "sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "prelude-ls": "^1.2.1"
+ },
+ "engines": {
+ "node": ">= 0.8.0"
+ }
+ },
+ "node_modules/typed-array-buffer": {
+ "version": "1.0.3",
+ "resolved": "https://registry.npmjs.org/typed-array-buffer/-/typed-array-buffer-1.0.3.tgz",
+ "integrity": "sha512-nAYYwfY3qnzX30IkA6AQZjVbtK6duGontcQm1WSG1MD94YLqK0515GNApXkoxKOWMusVssAHWLh9SeaoefYFGw==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "call-bound": "^1.0.3",
+ "es-errors": "^1.3.0",
+ "is-typed-array": "^1.1.14"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ }
+ },
+ "node_modules/typed-array-byte-length": {
+ "version": "1.0.3",
+ "resolved": "https://registry.npmjs.org/typed-array-byte-length/-/typed-array-byte-length-1.0.3.tgz",
+ "integrity": "sha512-BaXgOuIxz8n8pIq3e7Atg/7s+DpiYrxn4vdot3w9KbnBhcRQq6o3xemQdIfynqSeXeDrF32x+WvfzmOjPiY9lg==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "call-bind": "^1.0.8",
+ "for-each": "^0.3.3",
+ "gopd": "^1.2.0",
+ "has-proto": "^1.2.0",
+ "is-typed-array": "^1.1.14"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/typed-array-byte-offset": {
+ "version": "1.0.4",
+ "resolved": "https://registry.npmjs.org/typed-array-byte-offset/-/typed-array-byte-offset-1.0.4.tgz",
+ "integrity": "sha512-bTlAFB/FBYMcuX81gbL4OcpH5PmlFHqlCCpAl8AlEzMz5k53oNDvN8p1PNOWLEmI2x4orp3raOFB51tv9X+MFQ==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "available-typed-arrays": "^1.0.7",
+ "call-bind": "^1.0.8",
+ "for-each": "^0.3.3",
+ "gopd": "^1.2.0",
+ "has-proto": "^1.2.0",
+ "is-typed-array": "^1.1.15",
+ "reflect.getprototypeof": "^1.0.9"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/typed-array-length": {
+ "version": "1.0.7",
+ "resolved": "https://registry.npmjs.org/typed-array-length/-/typed-array-length-1.0.7.tgz",
+ "integrity": "sha512-3KS2b+kL7fsuk/eJZ7EQdnEmQoaho/r6KUef7hxvltNA5DR8NAUM+8wJMbJyZ4G9/7i3v5zPBIMN5aybAh2/Jg==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "call-bind": "^1.0.7",
+ "for-each": "^0.3.3",
+ "gopd": "^1.0.1",
+ "is-typed-array": "^1.1.13",
+ "possible-typed-array-names": "^1.0.0",
+ "reflect.getprototypeof": "^1.0.6"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/typescript": {
+ "version": "5.9.3",
+ "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.9.3.tgz",
+ "integrity": "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==",
+ "dev": true,
+ "license": "Apache-2.0",
+ "bin": {
+ "tsc": "bin/tsc",
+ "tsserver": "bin/tsserver"
+ },
+ "engines": {
+ "node": ">=14.17"
+ }
+ },
+ "node_modules/typescript-eslint": {
+ "version": "8.59.3",
+ "resolved": "https://registry.npmjs.org/typescript-eslint/-/typescript-eslint-8.59.3.tgz",
+ "integrity": "sha512-KgusgyDgG4LI8Ih/sWaCtZ06tckLAS5CvT5A4D1Q7bYVoAAyzwiZvE4BmwDHkhRVkvhRBepKeASoFzQetha7Fg==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@typescript-eslint/eslint-plugin": "8.59.3",
+ "@typescript-eslint/parser": "8.59.3",
+ "@typescript-eslint/typescript-estree": "8.59.3",
+ "@typescript-eslint/utils": "8.59.3"
+ },
+ "engines": {
+ "node": "^18.18.0 || ^20.9.0 || >=21.1.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/typescript-eslint"
+ },
+ "peerDependencies": {
+ "eslint": "^8.57.0 || ^9.0.0 || ^10.0.0",
+ "typescript": ">=4.8.4 <6.1.0"
+ }
+ },
+ "node_modules/unbox-primitive": {
+ "version": "1.1.0",
+ "resolved": "https://registry.npmjs.org/unbox-primitive/-/unbox-primitive-1.1.0.tgz",
+ "integrity": "sha512-nWJ91DjeOkej/TA8pXQ3myruKpKEYgqvpw9lz4OPHj/NWFNluYrjbz9j01CJ8yKQd2g4jFoOkINCTW2I5LEEyw==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "call-bound": "^1.0.3",
+ "has-bigints": "^1.0.2",
+ "has-symbols": "^1.1.0",
+ "which-boxed-primitive": "^1.1.1"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/undici": {
+ "version": "7.24.8",
+ "resolved": "https://registry.npmjs.org/undici/-/undici-7.24.8.tgz",
+ "integrity": "sha512-6KQ/+QxK49Z/p3HO6E5ZCZWNnCasyZLa5ExaVYyvPxUwKtbCPMKELJOqh7EqOle0t9cH/7d2TaaTRRa6Nhs4YQ==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=20.18.1"
+ }
+ },
+ "node_modules/undici-types": {
+ "version": "6.21.0",
+ "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-6.21.0.tgz",
+ "integrity": "sha512-iwDZqg0QAGrg9Rav5H4n0M64c3mkR59cJ6wQp+7C4nI0gsmExaedaYLNO44eT4AtBBwjbTiGPMlt2Md0T9H9JQ==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/unenv": {
+ "version": "2.0.0-rc.24",
+ "resolved": "https://registry.npmjs.org/unenv/-/unenv-2.0.0-rc.24.tgz",
+ "integrity": "sha512-i7qRCmY42zmCwnYlh9H2SvLEypEFGye5iRmEMKjcGi7zk9UquigRjFtTLz0TYqr0ZGLZhaMHl/foy1bZR+Cwlw==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "pathe": "^2.0.3"
+ }
+ },
+ "node_modules/unicode-trie": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/unicode-trie/-/unicode-trie-2.0.0.tgz",
+ "integrity": "sha512-x7bc76x0bm4prf1VLg79uhAzKw8DVboClSN5VxJuQ+LKDOVEW9CdH+VY7SP+vX7xCYQqzzgQpFqz15zeLvAtZQ==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "pako": "^0.2.5",
+ "tiny-inflate": "^1.0.0"
+ }
+ },
+ "node_modules/unpic": {
+ "version": "4.2.2",
+ "resolved": "https://registry.npmjs.org/unpic/-/unpic-4.2.2.tgz",
+ "integrity": "sha512-z6T2ScMgRV2y2H8MwwhY5xHZWXhUx/YxtOCGJwfURSl7ypVy4HpLIMWoIZKnnxQa/RKzM0kg8hUh0paIrpLfvw==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/unrs-resolver": {
+ "version": "1.11.1",
+ "resolved": "https://registry.npmjs.org/unrs-resolver/-/unrs-resolver-1.11.1.tgz",
+ "integrity": "sha512-bSjt9pjaEBnNiGgc9rUiHGKv5l4/TGzDmYw3RhnkJGtLhbnnA/5qJj7x3dNDCRx/PJxu774LlH8lCOlB4hEfKg==",
+ "dev": true,
+ "hasInstallScript": true,
+ "license": "MIT",
+ "dependencies": {
+ "napi-postinstall": "^0.3.0"
+ },
+ "funding": {
+ "url": "https://opencollective.com/unrs-resolver"
+ },
+ "optionalDependencies": {
+ "@unrs/resolver-binding-android-arm-eabi": "1.11.1",
+ "@unrs/resolver-binding-android-arm64": "1.11.1",
+ "@unrs/resolver-binding-darwin-arm64": "1.11.1",
+ "@unrs/resolver-binding-darwin-x64": "1.11.1",
+ "@unrs/resolver-binding-freebsd-x64": "1.11.1",
+ "@unrs/resolver-binding-linux-arm-gnueabihf": "1.11.1",
+ "@unrs/resolver-binding-linux-arm-musleabihf": "1.11.1",
+ "@unrs/resolver-binding-linux-arm64-gnu": "1.11.1",
+ "@unrs/resolver-binding-linux-arm64-musl": "1.11.1",
+ "@unrs/resolver-binding-linux-ppc64-gnu": "1.11.1",
+ "@unrs/resolver-binding-linux-riscv64-gnu": "1.11.1",
+ "@unrs/resolver-binding-linux-riscv64-musl": "1.11.1",
+ "@unrs/resolver-binding-linux-s390x-gnu": "1.11.1",
+ "@unrs/resolver-binding-linux-x64-gnu": "1.11.1",
+ "@unrs/resolver-binding-linux-x64-musl": "1.11.1",
+ "@unrs/resolver-binding-wasm32-wasi": "1.11.1",
+ "@unrs/resolver-binding-win32-arm64-msvc": "1.11.1",
+ "@unrs/resolver-binding-win32-ia32-msvc": "1.11.1",
+ "@unrs/resolver-binding-win32-x64-msvc": "1.11.1"
+ }
+ },
+ "node_modules/update-browserslist-db": {
+ "version": "1.2.3",
+ "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.2.3.tgz",
+ "integrity": "sha512-Js0m9cx+qOgDxo0eMiFGEueWztz+d4+M3rGlmKPT+T4IS/jP4ylw3Nwpu6cpTTP8R1MAC1kF4VbdLt3ARf209w==",
+ "dev": true,
+ "funding": [
+ {
+ "type": "opencollective",
+ "url": "https://opencollective.com/browserslist"
+ },
+ {
+ "type": "tidelift",
+ "url": "https://tidelift.com/funding/github/npm/browserslist"
+ },
+ {
+ "type": "github",
+ "url": "https://github.com/sponsors/ai"
+ }
+ ],
+ "license": "MIT",
+ "dependencies": {
+ "escalade": "^3.2.0",
+ "picocolors": "^1.1.1"
+ },
+ "bin": {
+ "update-browserslist-db": "cli.js"
+ },
+ "peerDependencies": {
+ "browserslist": ">= 4.21.0"
+ }
+ },
+ "node_modules/uri-js": {
+ "version": "4.4.1",
+ "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz",
+ "integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==",
+ "dev": true,
+ "license": "BSD-2-Clause",
+ "dependencies": {
+ "punycode": "^2.1.0"
+ }
+ },
+ "node_modules/vinext": {
+ "version": "0.0.50",
+ "resolved": "https://registry.npmjs.org/vinext/-/vinext-0.0.50.tgz",
+ "integrity": "sha512-uo72YNnq94NtogETWnhMdFSrkMLwWgeXh5PS6qh8ksajuvAaZX50bXYJ4a6dERQ/AnnXAlNByAGHCjjNxQrvig==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@unpic/react": "^1.0.2",
+ "@vercel/og": "^0.8.6",
+ "image-size": "2.0.2",
+ "ipaddr.js": "^2.1.0",
+ "magic-string": "^0.30.21",
+ "vite-plugin-commonjs": "^0.10.4",
+ "vite-tsconfig-paths": "^6.1.1",
+ "web-vitals": "^4.2.4"
+ },
+ "bin": {
+ "vinext": "dist/cli.js"
+ },
+ "engines": {
+ "node": ">=22"
+ },
+ "peerDependencies": {
+ "@mdx-js/rollup": "^3.0.0",
+ "@vitejs/plugin-react": "^5.1.4 || ^6.0.0",
+ "@vitejs/plugin-rsc": "^0.5.23",
+ "react": "^19.2.6",
+ "react-dom": "^19.2.6",
+ "react-server-dom-webpack": "^19.2.6",
+ "vite": "^7.0.0 || ^8.0.0"
+ },
+ "peerDependenciesMeta": {
+ "@mdx-js/rollup": {
+ "optional": true
+ },
+ "@vitejs/plugin-rsc": {
+ "optional": true
+ },
+ "react-server-dom-webpack": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/vite": {
+ "version": "8.0.13",
+ "resolved": "https://registry.npmjs.org/vite/-/vite-8.0.13.tgz",
+ "integrity": "sha512-MFtjBYgzmSxmgA4RAfjIyXWpGe1oALnjgUTzzV7QLx/TKxCzjtMH6Fd9/eVK+5Fg1qNoz5VAwsmMs/NofrmJvw==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "lightningcss": "^1.32.0",
+ "picomatch": "^4.0.4",
+ "postcss": "^8.5.14",
+ "rolldown": "1.0.1",
+ "tinyglobby": "^0.2.16"
+ },
+ "bin": {
+ "vite": "bin/vite.js"
+ },
+ "engines": {
+ "node": "^20.19.0 || >=22.12.0"
+ },
+ "funding": {
+ "url": "https://github.com/vitejs/vite?sponsor=1"
+ },
+ "optionalDependencies": {
+ "fsevents": "~2.3.3"
+ },
+ "peerDependencies": {
+ "@types/node": "^20.19.0 || >=22.12.0",
+ "@vitejs/devtools": "^0.1.18",
+ "esbuild": "^0.27.0 || ^0.28.0",
+ "jiti": ">=1.21.0",
+ "less": "^4.0.0",
+ "sass": "^1.70.0",
+ "sass-embedded": "^1.70.0",
+ "stylus": ">=0.54.8",
+ "sugarss": "^5.0.0",
+ "terser": "^5.16.0",
+ "tsx": "^4.8.1",
+ "yaml": "^2.4.2"
+ },
+ "peerDependenciesMeta": {
+ "@types/node": {
+ "optional": true
+ },
+ "@vitejs/devtools": {
+ "optional": true
+ },
+ "esbuild": {
+ "optional": true
+ },
+ "jiti": {
+ "optional": true
+ },
+ "less": {
+ "optional": true
+ },
+ "sass": {
+ "optional": true
+ },
+ "sass-embedded": {
+ "optional": true
+ },
+ "stylus": {
+ "optional": true
+ },
+ "sugarss": {
+ "optional": true
+ },
+ "terser": {
+ "optional": true
+ },
+ "tsx": {
+ "optional": true
+ },
+ "yaml": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/vite-plugin-commonjs": {
+ "version": "0.10.4",
+ "resolved": "https://registry.npmjs.org/vite-plugin-commonjs/-/vite-plugin-commonjs-0.10.4.tgz",
+ "integrity": "sha512-eWQuvQKCcx0QYB5e5xfxBNjQKyrjEWZIR9UOkOV6JAgxVhtbZvCOF+FNC2ZijBJ3U3Px04ZMMyyMyFBVWIJ5+g==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "acorn": "^8.12.1",
+ "magic-string": "^0.30.11",
+ "vite-plugin-dynamic-import": "^1.6.0"
+ }
+ },
+ "node_modules/vite-plugin-dynamic-import": {
+ "version": "1.6.0",
+ "resolved": "https://registry.npmjs.org/vite-plugin-dynamic-import/-/vite-plugin-dynamic-import-1.6.0.tgz",
+ "integrity": "sha512-TM0sz70wfzTIo9YCxVFwS8OA9lNREsh+0vMHGSkWDTZ7bgd1Yjs5RV8EgB634l/91IsXJReg0xtmuQqP0mf+rg==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "acorn": "^8.12.1",
+ "es-module-lexer": "^1.5.4",
+ "fast-glob": "^3.3.2",
+ "magic-string": "^0.30.11"
+ }
+ },
+ "node_modules/vite-plugin-dynamic-import/node_modules/es-module-lexer": {
+ "version": "1.7.0",
+ "resolved": "https://registry.npmjs.org/es-module-lexer/-/es-module-lexer-1.7.0.tgz",
+ "integrity": "sha512-jEQoCwk8hyb2AZziIOLhDqpm5+2ww5uIE6lkO/6jcOCusfk6LhMHpXXfBLXTZ7Ydyt0j4VoUQv6uGNYbdW+kBA==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/vite-plugin-dynamic-import/node_modules/fast-glob": {
+ "version": "3.3.3",
+ "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.3.3.tgz",
+ "integrity": "sha512-7MptL8U0cqcFdzIzwOTHoilX9x5BrNqye7Z/LuC7kCMRio1EMSyqRK3BEAUD7sXRq4iT4AzTVuZdhgQ2TCvYLg==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@nodelib/fs.stat": "^2.0.2",
+ "@nodelib/fs.walk": "^1.2.3",
+ "glob-parent": "^5.1.2",
+ "merge2": "^1.3.0",
+ "micromatch": "^4.0.8"
+ },
+ "engines": {
+ "node": ">=8.6.0"
+ }
+ },
+ "node_modules/vite-plugin-dynamic-import/node_modules/glob-parent": {
+ "version": "5.1.2",
+ "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz",
+ "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==",
+ "dev": true,
+ "license": "ISC",
+ "dependencies": {
+ "is-glob": "^4.0.1"
+ },
+ "engines": {
+ "node": ">= 6"
+ }
+ },
+ "node_modules/vite-tsconfig-paths": {
+ "version": "6.1.1",
+ "resolved": "https://registry.npmjs.org/vite-tsconfig-paths/-/vite-tsconfig-paths-6.1.1.tgz",
+ "integrity": "sha512-2cihq7zliibCCZ8P9cKJrQBkfgdvcFkOOc3Y02o3GWUDLgqjWsZudaoiuOwO/gzTzy17cS5F7ZPo4bsnS4DGkg==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "debug": "^4.1.1",
+ "globrex": "^0.1.2",
+ "tsconfck": "^3.0.3"
+ },
+ "peerDependencies": {
+ "vite": "*"
+ }
+ },
+ "node_modules/vite/node_modules/lightningcss": {
+ "version": "1.32.0",
+ "resolved": "https://registry.npmjs.org/lightningcss/-/lightningcss-1.32.0.tgz",
+ "integrity": "sha512-NXYBzinNrblfraPGyrbPoD19C1h9lfI/1mzgWYvXUTe414Gz/X1FD2XBZSZM7rRTrMA8JL3OtAaGifrIKhQ5yQ==",
+ "dev": true,
+ "license": "MPL-2.0",
+ "dependencies": {
+ "detect-libc": "^2.0.3"
+ },
+ "engines": {
+ "node": ">= 12.0.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/parcel"
+ },
+ "optionalDependencies": {
+ "lightningcss-android-arm64": "1.32.0",
+ "lightningcss-darwin-arm64": "1.32.0",
+ "lightningcss-darwin-x64": "1.32.0",
+ "lightningcss-freebsd-x64": "1.32.0",
+ "lightningcss-linux-arm-gnueabihf": "1.32.0",
+ "lightningcss-linux-arm64-gnu": "1.32.0",
+ "lightningcss-linux-arm64-musl": "1.32.0",
+ "lightningcss-linux-x64-gnu": "1.32.0",
+ "lightningcss-linux-x64-musl": "1.32.0",
+ "lightningcss-win32-arm64-msvc": "1.32.0",
+ "lightningcss-win32-x64-msvc": "1.32.0"
+ }
+ },
+ "node_modules/vite/node_modules/lightningcss-android-arm64": {
+ "version": "1.32.0",
+ "resolved": "https://registry.npmjs.org/lightningcss-android-arm64/-/lightningcss-android-arm64-1.32.0.tgz",
+ "integrity": "sha512-YK7/ClTt4kAK0vo6w3X+Pnm0D2cf2vPHbhOXdoNti1Ga0al1P4TBZhwjATvjNwLEBCnKvjJc2jQgHXH0NEwlAg==",
+ "cpu": [
+ "arm64"
+ ],
+ "dev": true,
+ "license": "MPL-2.0",
+ "optional": true,
+ "os": [
+ "android"
+ ],
+ "engines": {
+ "node": ">= 12.0.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/parcel"
+ }
+ },
+ "node_modules/vite/node_modules/lightningcss-darwin-arm64": {
+ "version": "1.32.0",
+ "resolved": "https://registry.npmjs.org/lightningcss-darwin-arm64/-/lightningcss-darwin-arm64-1.32.0.tgz",
+ "integrity": "sha512-RzeG9Ju5bag2Bv1/lwlVJvBE3q6TtXskdZLLCyfg5pt+HLz9BqlICO7LZM7VHNTTn/5PRhHFBSjk5lc4cmscPQ==",
+ "cpu": [
+ "arm64"
+ ],
+ "dev": true,
+ "license": "MPL-2.0",
+ "optional": true,
+ "os": [
+ "darwin"
+ ],
+ "engines": {
+ "node": ">= 12.0.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/parcel"
+ }
+ },
+ "node_modules/vite/node_modules/lightningcss-darwin-x64": {
+ "version": "1.32.0",
+ "resolved": "https://registry.npmjs.org/lightningcss-darwin-x64/-/lightningcss-darwin-x64-1.32.0.tgz",
+ "integrity": "sha512-U+QsBp2m/s2wqpUYT/6wnlagdZbtZdndSmut/NJqlCcMLTWp5muCrID+K5UJ6jqD2BFshejCYXniPDbNh73V8w==",
+ "cpu": [
+ "x64"
+ ],
+ "dev": true,
+ "license": "MPL-2.0",
+ "optional": true,
+ "os": [
+ "darwin"
+ ],
+ "engines": {
+ "node": ">= 12.0.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/parcel"
+ }
+ },
+ "node_modules/vite/node_modules/lightningcss-freebsd-x64": {
+ "version": "1.32.0",
+ "resolved": "https://registry.npmjs.org/lightningcss-freebsd-x64/-/lightningcss-freebsd-x64-1.32.0.tgz",
+ "integrity": "sha512-JCTigedEksZk3tHTTthnMdVfGf61Fky8Ji2E4YjUTEQX14xiy/lTzXnu1vwiZe3bYe0q+SpsSH/CTeDXK6WHig==",
+ "cpu": [
+ "x64"
+ ],
+ "dev": true,
+ "license": "MPL-2.0",
+ "optional": true,
+ "os": [
+ "freebsd"
+ ],
+ "engines": {
+ "node": ">= 12.0.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/parcel"
+ }
+ },
+ "node_modules/vite/node_modules/lightningcss-linux-arm-gnueabihf": {
+ "version": "1.32.0",
+ "resolved": "https://registry.npmjs.org/lightningcss-linux-arm-gnueabihf/-/lightningcss-linux-arm-gnueabihf-1.32.0.tgz",
+ "integrity": "sha512-x6rnnpRa2GL0zQOkt6rts3YDPzduLpWvwAF6EMhXFVZXD4tPrBkEFqzGowzCsIWsPjqSK+tyNEODUBXeeVHSkw==",
+ "cpu": [
+ "arm"
+ ],
+ "dev": true,
+ "license": "MPL-2.0",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">= 12.0.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/parcel"
+ }
+ },
+ "node_modules/vite/node_modules/lightningcss-linux-arm64-gnu": {
+ "version": "1.32.0",
+ "resolved": "https://registry.npmjs.org/lightningcss-linux-arm64-gnu/-/lightningcss-linux-arm64-gnu-1.32.0.tgz",
+ "integrity": "sha512-0nnMyoyOLRJXfbMOilaSRcLH3Jw5z9HDNGfT/gwCPgaDjnx0i8w7vBzFLFR1f6CMLKF8gVbebmkUN3fa/kQJpQ==",
+ "cpu": [
+ "arm64"
+ ],
+ "dev": true,
+ "license": "MPL-2.0",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">= 12.0.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/parcel"
+ }
+ },
+ "node_modules/vite/node_modules/lightningcss-linux-arm64-musl": {
+ "version": "1.32.0",
+ "resolved": "https://registry.npmjs.org/lightningcss-linux-arm64-musl/-/lightningcss-linux-arm64-musl-1.32.0.tgz",
+ "integrity": "sha512-UpQkoenr4UJEzgVIYpI80lDFvRmPVg6oqboNHfoH4CQIfNA+HOrZ7Mo7KZP02dC6LjghPQJeBsvXhJod/wnIBg==",
+ "cpu": [
+ "arm64"
+ ],
+ "dev": true,
+ "license": "MPL-2.0",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">= 12.0.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/parcel"
+ }
+ },
+ "node_modules/vite/node_modules/lightningcss-linux-x64-gnu": {
+ "version": "1.32.0",
+ "resolved": "https://registry.npmjs.org/lightningcss-linux-x64-gnu/-/lightningcss-linux-x64-gnu-1.32.0.tgz",
+ "integrity": "sha512-V7Qr52IhZmdKPVr+Vtw8o+WLsQJYCTd8loIfpDaMRWGUZfBOYEJeyJIkqGIDMZPwPx24pUMfwSxxI8phr/MbOA==",
+ "cpu": [
+ "x64"
+ ],
+ "dev": true,
+ "license": "MPL-2.0",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">= 12.0.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/parcel"
+ }
+ },
+ "node_modules/vite/node_modules/lightningcss-linux-x64-musl": {
+ "version": "1.32.0",
+ "resolved": "https://registry.npmjs.org/lightningcss-linux-x64-musl/-/lightningcss-linux-x64-musl-1.32.0.tgz",
+ "integrity": "sha512-bYcLp+Vb0awsiXg/80uCRezCYHNg1/l3mt0gzHnWV9XP1W5sKa5/TCdGWaR/zBM2PeF/HbsQv/j2URNOiVuxWg==",
+ "cpu": [
+ "x64"
+ ],
+ "dev": true,
+ "license": "MPL-2.0",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">= 12.0.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/parcel"
+ }
+ },
+ "node_modules/vite/node_modules/lightningcss-win32-arm64-msvc": {
+ "version": "1.32.0",
+ "resolved": "https://registry.npmjs.org/lightningcss-win32-arm64-msvc/-/lightningcss-win32-arm64-msvc-1.32.0.tgz",
+ "integrity": "sha512-8SbC8BR40pS6baCM8sbtYDSwEVQd4JlFTOlaD3gWGHfThTcABnNDBda6eTZeqbofalIJhFx0qKzgHJmcPTnGdw==",
+ "cpu": [
+ "arm64"
+ ],
+ "dev": true,
+ "license": "MPL-2.0",
+ "optional": true,
+ "os": [
+ "win32"
+ ],
+ "engines": {
+ "node": ">= 12.0.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/parcel"
+ }
+ },
+ "node_modules/vite/node_modules/lightningcss-win32-x64-msvc": {
+ "version": "1.32.0",
+ "resolved": "https://registry.npmjs.org/lightningcss-win32-x64-msvc/-/lightningcss-win32-x64-msvc-1.32.0.tgz",
+ "integrity": "sha512-Amq9B/SoZYdDi1kFrojnoqPLxYhQ4Wo5XiL8EVJrVsB8ARoC1PWW6VGtT0WKCemjy8aC+louJnjS7U18x3b06Q==",
+ "cpu": [
+ "x64"
+ ],
+ "dev": true,
+ "license": "MPL-2.0",
+ "optional": true,
+ "os": [
+ "win32"
+ ],
+ "engines": {
+ "node": ">= 12.0.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/parcel"
+ }
+ },
+ "node_modules/vite/node_modules/picomatch": {
+ "version": "4.0.4",
+ "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.4.tgz",
+ "integrity": "sha512-QP88BAKvMam/3NxH6vj2o21R6MjxZUAd6nlwAS/pnGvN9IVLocLHxGYIzFhg6fUQ+5th6P4dv4eW9jX3DSIj7A==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=12"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/jonschlinkert"
+ }
+ },
+ "node_modules/vitefu": {
+ "version": "1.1.3",
+ "resolved": "https://registry.npmjs.org/vitefu/-/vitefu-1.1.3.tgz",
+ "integrity": "sha512-ub4okH7Z5KLjb6hDyjqrGXqWtWvoYdU3IGm/NorpgHncKoLTCfRIbvlhBm7r0YstIaQRYlp4yEbFqDcKSzXSSg==",
+ "dev": true,
+ "license": "MIT",
+ "workspaces": [
+ "tests/deps/*",
+ "tests/projects/*",
+ "tests/projects/workspace/packages/*"
+ ],
+ "peerDependencies": {
+ "vite": "^3.0.0 || ^4.0.0 || ^5.0.0 || ^6.0.0 || ^7.0.0 || ^8.0.0"
+ },
+ "peerDependenciesMeta": {
+ "vite": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/watchpack": {
+ "version": "2.5.1",
+ "resolved": "https://registry.npmjs.org/watchpack/-/watchpack-2.5.1.tgz",
+ "integrity": "sha512-Zn5uXdcFNIA1+1Ei5McRd+iRzfhENPCe7LeABkJtNulSxjma+l7ltNx55BWZkRlwRnpOgHqxnjyaDgJnNXnqzg==",
+ "dev": true,
+ "license": "MIT",
+ "peer": true,
+ "dependencies": {
+ "glob-to-regexp": "^0.4.1",
+ "graceful-fs": "^4.1.2"
+ },
+ "engines": {
+ "node": ">=10.13.0"
+ }
+ },
+ "node_modules/web-vitals": {
+ "version": "4.2.4",
+ "resolved": "https://registry.npmjs.org/web-vitals/-/web-vitals-4.2.4.tgz",
+ "integrity": "sha512-r4DIlprAGwJ7YM11VZp4R884m0Vmgr6EAKe3P+kO0PPj3Unqyvv59rczf6UiGcb9Z8QxZVcqKNwv/g0WNdWwsw==",
+ "dev": true,
+ "license": "Apache-2.0"
+ },
+ "node_modules/webpack": {
+ "version": "5.106.2",
+ "resolved": "https://registry.npmjs.org/webpack/-/webpack-5.106.2.tgz",
+ "integrity": "sha512-wGN3qcrBQIFmQ/c0AiOAQBvrZ5lmY8vbbMv4Mxfgzqd/B6+9pXtLo73WuS1dSGXM5QYY3hZnIbvx+K1xxe6FyA==",
+ "dev": true,
+ "license": "MIT",
+ "peer": true,
+ "dependencies": {
+ "@types/eslint-scope": "^3.7.7",
+ "@types/estree": "^1.0.8",
+ "@types/json-schema": "^7.0.15",
+ "@webassemblyjs/ast": "^1.14.1",
+ "@webassemblyjs/wasm-edit": "^1.14.1",
+ "@webassemblyjs/wasm-parser": "^1.14.1",
+ "acorn": "^8.16.0",
+ "acorn-import-phases": "^1.0.3",
+ "browserslist": "^4.28.1",
+ "chrome-trace-event": "^1.0.2",
+ "enhanced-resolve": "^5.20.0",
+ "es-module-lexer": "^2.0.0",
+ "eslint-scope": "5.1.1",
+ "events": "^3.2.0",
+ "glob-to-regexp": "^0.4.1",
+ "graceful-fs": "^4.2.11",
+ "loader-runner": "^4.3.1",
+ "mime-db": "^1.54.0",
+ "neo-async": "^2.6.2",
+ "schema-utils": "^4.3.3",
+ "tapable": "^2.3.0",
+ "terser-webpack-plugin": "^5.3.17",
+ "watchpack": "^2.5.1",
+ "webpack-sources": "^3.3.4"
+ },
+ "bin": {
+ "webpack": "bin/webpack.js"
+ },
+ "engines": {
+ "node": ">=10.13.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/webpack"
+ },
+ "peerDependenciesMeta": {
+ "webpack-cli": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/webpack-sources": {
+ "version": "3.4.1",
+ "resolved": "https://registry.npmjs.org/webpack-sources/-/webpack-sources-3.4.1.tgz",
+ "integrity": "sha512-eACpxRN02yaawnt+uUNIF7Qje6A9zArxBbcAJjK1PK3S9Ycg5jIuJ8pW4q8EMnwNZCEGltcjkRx1QzOxOkKD8A==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=10.13.0"
+ }
+ },
+ "node_modules/webpack/node_modules/eslint-scope": {
+ "version": "5.1.1",
+ "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-5.1.1.tgz",
+ "integrity": "sha512-2NxwbF/hZ0KpepYN0cNbo+FN6XoK7GaHlQhgx/hIZl6Va0bF45RQOOwhLIy8lQDbuCiadSLCBnH2CFYquit5bw==",
+ "dev": true,
+ "license": "BSD-2-Clause",
+ "peer": true,
+ "dependencies": {
+ "esrecurse": "^4.3.0",
+ "estraverse": "^4.1.1"
+ },
+ "engines": {
+ "node": ">=8.0.0"
+ }
+ },
+ "node_modules/webpack/node_modules/estraverse": {
+ "version": "4.3.0",
+ "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.3.0.tgz",
+ "integrity": "sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==",
+ "dev": true,
+ "license": "BSD-2-Clause",
+ "peer": true,
+ "engines": {
+ "node": ">=4.0"
+ }
+ },
+ "node_modules/which": {
+ "version": "2.0.2",
+ "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz",
+ "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==",
+ "dev": true,
+ "license": "ISC",
+ "dependencies": {
+ "isexe": "^2.0.0"
+ },
+ "bin": {
+ "node-which": "bin/node-which"
+ },
+ "engines": {
+ "node": ">= 8"
+ }
+ },
+ "node_modules/which-boxed-primitive": {
+ "version": "1.1.1",
+ "resolved": "https://registry.npmjs.org/which-boxed-primitive/-/which-boxed-primitive-1.1.1.tgz",
+ "integrity": "sha512-TbX3mj8n0odCBFVlY8AxkqcHASw3L60jIuF8jFP78az3C2YhmGvqbHBpAjTRH2/xqYunrJ9g1jSyjCjpoWzIAA==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "is-bigint": "^1.1.0",
+ "is-boolean-object": "^1.2.1",
+ "is-number-object": "^1.1.1",
+ "is-string": "^1.1.1",
+ "is-symbol": "^1.1.1"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/which-builtin-type": {
+ "version": "1.2.1",
+ "resolved": "https://registry.npmjs.org/which-builtin-type/-/which-builtin-type-1.2.1.tgz",
+ "integrity": "sha512-6iBczoX+kDQ7a3+YJBnh3T+KZRxM/iYNPXicqk66/Qfm1b93iu+yOImkg0zHbj5LNOcNv1TEADiZ0xa34B4q6Q==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "call-bound": "^1.0.2",
+ "function.prototype.name": "^1.1.6",
+ "has-tostringtag": "^1.0.2",
+ "is-async-function": "^2.0.0",
+ "is-date-object": "^1.1.0",
+ "is-finalizationregistry": "^1.1.0",
+ "is-generator-function": "^1.0.10",
+ "is-regex": "^1.2.1",
+ "is-weakref": "^1.0.2",
+ "isarray": "^2.0.5",
+ "which-boxed-primitive": "^1.1.0",
+ "which-collection": "^1.0.2",
+ "which-typed-array": "^1.1.16"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/which-collection": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/which-collection/-/which-collection-1.0.2.tgz",
+ "integrity": "sha512-K4jVyjnBdgvc86Y6BkaLZEN933SwYOuBFkdmBu9ZfkcAbdVbpITnDmjvZ/aQjRXQrv5EPkTnD1s39GiiqbngCw==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "is-map": "^2.0.3",
+ "is-set": "^2.0.3",
+ "is-weakmap": "^2.0.2",
+ "is-weakset": "^2.0.3"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/which-typed-array": {
+ "version": "1.1.20",
+ "resolved": "https://registry.npmjs.org/which-typed-array/-/which-typed-array-1.1.20.tgz",
+ "integrity": "sha512-LYfpUkmqwl0h9A2HL09Mms427Q1RZWuOHsukfVcKRq9q95iQxdw0ix1JQrqbcDR9PH1QDwf5Qo8OZb5lksZ8Xg==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "available-typed-arrays": "^1.0.7",
+ "call-bind": "^1.0.8",
+ "call-bound": "^1.0.4",
+ "for-each": "^0.3.5",
+ "get-proto": "^1.0.1",
+ "gopd": "^1.2.0",
+ "has-tostringtag": "^1.0.2"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/word-wrap": {
+ "version": "1.2.5",
+ "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.5.tgz",
+ "integrity": "sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/workerd": {
+ "version": "1.20260515.1",
+ "resolved": "https://registry.npmjs.org/workerd/-/workerd-1.20260515.1.tgz",
+ "integrity": "sha512-MjKOJLcvU45xXedQowvuiHtJTxu4WTHYQeIlF7YmjuqhiI6dImTFxWCEoRQHiskztxuVSNEmdO7/0UfDu6OMnQ==",
+ "dev": true,
+ "hasInstallScript": true,
+ "license": "Apache-2.0",
+ "bin": {
+ "workerd": "bin/workerd"
+ },
+ "engines": {
+ "node": ">=16"
+ },
+ "optionalDependencies": {
+ "@cloudflare/workerd-darwin-64": "1.20260515.1",
+ "@cloudflare/workerd-darwin-arm64": "1.20260515.1",
+ "@cloudflare/workerd-linux-64": "1.20260515.1",
+ "@cloudflare/workerd-linux-arm64": "1.20260515.1",
+ "@cloudflare/workerd-windows-64": "1.20260515.1"
+ }
+ },
+ "node_modules/wrangler": {
+ "version": "4.92.0",
+ "resolved": "https://registry.npmjs.org/wrangler/-/wrangler-4.92.0.tgz",
+ "integrity": "sha512-/DKpQHPxkuZbQsO9dFW2700VTD/4DSZMHjy92fO/frNoDRi/zQsFCAd2ONCV6TGqcUoXcP3D8Bo2gj/L4M0qQQ==",
+ "dev": true,
+ "license": "MIT OR Apache-2.0",
+ "dependencies": {
+ "@cloudflare/kv-asset-handler": "0.5.0",
+ "@cloudflare/unenv-preset": "2.16.1",
+ "blake3-wasm": "2.1.5",
+ "esbuild": "0.27.3",
+ "miniflare": "4.20260515.0",
+ "path-to-regexp": "6.3.0",
+ "unenv": "2.0.0-rc.24",
+ "workerd": "1.20260515.1"
+ },
+ "bin": {
+ "wrangler": "bin/wrangler.js",
+ "wrangler2": "bin/wrangler.js"
+ },
+ "engines": {
+ "node": ">=22.0.0"
+ },
+ "optionalDependencies": {
+ "fsevents": "~2.3.2"
+ },
+ "peerDependencies": {
+ "@cloudflare/workers-types": "^4.20260515.1"
+ },
+ "peerDependenciesMeta": {
+ "@cloudflare/workers-types": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/wrangler/node_modules/@esbuild/aix-ppc64": {
+ "version": "0.27.3",
+ "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.27.3.tgz",
+ "integrity": "sha512-9fJMTNFTWZMh5qwrBItuziu834eOCUcEqymSH7pY+zoMVEZg3gcPuBNxH1EvfVYe9h0x/Ptw8KBzv7qxb7l8dg==",
+ "cpu": [
+ "ppc64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "aix"
+ ],
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/wrangler/node_modules/@esbuild/android-arm": {
+ "version": "0.27.3",
+ "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.27.3.tgz",
+ "integrity": "sha512-i5D1hPY7GIQmXlXhs2w8AWHhenb00+GxjxRncS2ZM7YNVGNfaMxgzSGuO8o8SJzRc/oZwU2bcScvVERk03QhzA==",
+ "cpu": [
+ "arm"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "android"
+ ],
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/wrangler/node_modules/@esbuild/android-arm64": {
+ "version": "0.27.3",
+ "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.27.3.tgz",
+ "integrity": "sha512-YdghPYUmj/FX2SYKJ0OZxf+iaKgMsKHVPF1MAq/P8WirnSpCStzKJFjOjzsW0QQ7oIAiccHdcqjbHmJxRb/dmg==",
+ "cpu": [
+ "arm64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "android"
+ ],
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/wrangler/node_modules/@esbuild/android-x64": {
+ "version": "0.27.3",
+ "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.27.3.tgz",
+ "integrity": "sha512-IN/0BNTkHtk8lkOM8JWAYFg4ORxBkZQf9zXiEOfERX/CzxW3Vg1ewAhU7QSWQpVIzTW+b8Xy+lGzdYXV6UZObQ==",
+ "cpu": [
+ "x64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "android"
+ ],
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/wrangler/node_modules/@esbuild/darwin-arm64": {
+ "version": "0.27.3",
+ "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.27.3.tgz",
+ "integrity": "sha512-Re491k7ByTVRy0t3EKWajdLIr0gz2kKKfzafkth4Q8A5n1xTHrkqZgLLjFEHVD+AXdUGgQMq+Godfq45mGpCKg==",
+ "cpu": [
+ "arm64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "darwin"
+ ],
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/wrangler/node_modules/@esbuild/darwin-x64": {
+ "version": "0.27.3",
+ "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.27.3.tgz",
+ "integrity": "sha512-vHk/hA7/1AckjGzRqi6wbo+jaShzRowYip6rt6q7VYEDX4LEy1pZfDpdxCBnGtl+A5zq8iXDcyuxwtv3hNtHFg==",
+ "cpu": [
+ "x64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "darwin"
+ ],
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/wrangler/node_modules/@esbuild/freebsd-arm64": {
+ "version": "0.27.3",
+ "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.27.3.tgz",
+ "integrity": "sha512-ipTYM2fjt3kQAYOvo6vcxJx3nBYAzPjgTCk7QEgZG8AUO3ydUhvelmhrbOheMnGOlaSFUoHXB6un+A7q4ygY9w==",
+ "cpu": [
+ "arm64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "freebsd"
+ ],
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/wrangler/node_modules/@esbuild/freebsd-x64": {
+ "version": "0.27.3",
+ "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.27.3.tgz",
+ "integrity": "sha512-dDk0X87T7mI6U3K9VjWtHOXqwAMJBNN2r7bejDsc+j03SEjtD9HrOl8gVFByeM0aJksoUuUVU9TBaZa2rgj0oA==",
+ "cpu": [
+ "x64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "freebsd"
+ ],
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/wrangler/node_modules/@esbuild/linux-arm": {
+ "version": "0.27.3",
+ "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.27.3.tgz",
+ "integrity": "sha512-s6nPv2QkSupJwLYyfS+gwdirm0ukyTFNl3KTgZEAiJDd+iHZcbTPPcWCcRYH+WlNbwChgH2QkE9NSlNrMT8Gfw==",
+ "cpu": [
+ "arm"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/wrangler/node_modules/@esbuild/linux-arm64": {
+ "version": "0.27.3",
+ "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.27.3.tgz",
+ "integrity": "sha512-sZOuFz/xWnZ4KH3YfFrKCf1WyPZHakVzTiqji3WDc0BCl2kBwiJLCXpzLzUBLgmp4veFZdvN5ChW4Eq/8Fc2Fg==",
+ "cpu": [
+ "arm64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/wrangler/node_modules/@esbuild/linux-ia32": {
+ "version": "0.27.3",
+ "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.27.3.tgz",
+ "integrity": "sha512-yGlQYjdxtLdh0a3jHjuwOrxQjOZYD/C9PfdbgJJF3TIZWnm/tMd/RcNiLngiu4iwcBAOezdnSLAwQDPqTmtTYg==",
+ "cpu": [
+ "ia32"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/wrangler/node_modules/@esbuild/linux-loong64": {
+ "version": "0.27.3",
+ "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.27.3.tgz",
+ "integrity": "sha512-WO60Sn8ly3gtzhyjATDgieJNet/KqsDlX5nRC5Y3oTFcS1l0KWba+SEa9Ja1GfDqSF1z6hif/SkpQJbL63cgOA==",
+ "cpu": [
+ "loong64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/wrangler/node_modules/@esbuild/linux-mips64el": {
+ "version": "0.27.3",
+ "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.27.3.tgz",
+ "integrity": "sha512-APsymYA6sGcZ4pD6k+UxbDjOFSvPWyZhjaiPyl/f79xKxwTnrn5QUnXR5prvetuaSMsb4jgeHewIDCIWljrSxw==",
+ "cpu": [
+ "mips64el"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/wrangler/node_modules/@esbuild/linux-ppc64": {
+ "version": "0.27.3",
+ "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.27.3.tgz",
+ "integrity": "sha512-eizBnTeBefojtDb9nSh4vvVQ3V9Qf9Df01PfawPcRzJH4gFSgrObw+LveUyDoKU3kxi5+9RJTCWlj4FjYXVPEA==",
+ "cpu": [
+ "ppc64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/wrangler/node_modules/@esbuild/linux-riscv64": {
+ "version": "0.27.3",
+ "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.27.3.tgz",
+ "integrity": "sha512-3Emwh0r5wmfm3ssTWRQSyVhbOHvqegUDRd0WhmXKX2mkHJe1SFCMJhagUleMq+Uci34wLSipf8Lagt4LlpRFWQ==",
+ "cpu": [
+ "riscv64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/wrangler/node_modules/@esbuild/linux-s390x": {
+ "version": "0.27.3",
+ "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.27.3.tgz",
+ "integrity": "sha512-pBHUx9LzXWBc7MFIEEL0yD/ZVtNgLytvx60gES28GcWMqil8ElCYR4kvbV2BDqsHOvVDRrOxGySBM9Fcv744hw==",
+ "cpu": [
+ "s390x"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/wrangler/node_modules/@esbuild/linux-x64": {
+ "version": "0.27.3",
+ "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.27.3.tgz",
+ "integrity": "sha512-Czi8yzXUWIQYAtL/2y6vogER8pvcsOsk5cpwL4Gk5nJqH5UZiVByIY8Eorm5R13gq+DQKYg0+JyQoytLQas4dA==",
+ "cpu": [
+ "x64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/wrangler/node_modules/@esbuild/netbsd-arm64": {
+ "version": "0.27.3",
+ "resolved": "https://registry.npmjs.org/@esbuild/netbsd-arm64/-/netbsd-arm64-0.27.3.tgz",
+ "integrity": "sha512-sDpk0RgmTCR/5HguIZa9n9u+HVKf40fbEUt+iTzSnCaGvY9kFP0YKBWZtJaraonFnqef5SlJ8/TiPAxzyS+UoA==",
+ "cpu": [
+ "arm64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "netbsd"
+ ],
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/wrangler/node_modules/@esbuild/netbsd-x64": {
+ "version": "0.27.3",
+ "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.27.3.tgz",
+ "integrity": "sha512-P14lFKJl/DdaE00LItAukUdZO5iqNH7+PjoBm+fLQjtxfcfFE20Xf5CrLsmZdq5LFFZzb5JMZ9grUwvtVYzjiA==",
+ "cpu": [
+ "x64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "netbsd"
+ ],
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/wrangler/node_modules/@esbuild/openbsd-arm64": {
+ "version": "0.27.3",
+ "resolved": "https://registry.npmjs.org/@esbuild/openbsd-arm64/-/openbsd-arm64-0.27.3.tgz",
+ "integrity": "sha512-AIcMP77AvirGbRl/UZFTq5hjXK+2wC7qFRGoHSDrZ5v5b8DK/GYpXW3CPRL53NkvDqb9D+alBiC/dV0Fb7eJcw==",
+ "cpu": [
+ "arm64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "openbsd"
+ ],
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/wrangler/node_modules/@esbuild/openbsd-x64": {
+ "version": "0.27.3",
+ "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.27.3.tgz",
+ "integrity": "sha512-DnW2sRrBzA+YnE70LKqnM3P+z8vehfJWHXECbwBmH/CU51z6FiqTQTHFenPlHmo3a8UgpLyH3PT+87OViOh1AQ==",
+ "cpu": [
+ "x64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "openbsd"
+ ],
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/wrangler/node_modules/@esbuild/openharmony-arm64": {
+ "version": "0.27.3",
+ "resolved": "https://registry.npmjs.org/@esbuild/openharmony-arm64/-/openharmony-arm64-0.27.3.tgz",
+ "integrity": "sha512-NinAEgr/etERPTsZJ7aEZQvvg/A6IsZG/LgZy+81wON2huV7SrK3e63dU0XhyZP4RKGyTm7aOgmQk0bGp0fy2g==",
+ "cpu": [
+ "arm64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "openharmony"
+ ],
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/wrangler/node_modules/@esbuild/sunos-x64": {
+ "version": "0.27.3",
+ "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.27.3.tgz",
+ "integrity": "sha512-PanZ+nEz+eWoBJ8/f8HKxTTD172SKwdXebZ0ndd953gt1HRBbhMsaNqjTyYLGLPdoWHy4zLU7bDVJztF5f3BHA==",
+ "cpu": [
+ "x64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "sunos"
+ ],
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/wrangler/node_modules/@esbuild/win32-arm64": {
+ "version": "0.27.3",
+ "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.27.3.tgz",
+ "integrity": "sha512-B2t59lWWYrbRDw/tjiWOuzSsFh1Y/E95ofKz7rIVYSQkUYBjfSgf6oeYPNWHToFRr2zx52JKApIcAS/D5TUBnA==",
+ "cpu": [
+ "arm64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "win32"
+ ],
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/wrangler/node_modules/@esbuild/win32-ia32": {
+ "version": "0.27.3",
+ "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.27.3.tgz",
+ "integrity": "sha512-QLKSFeXNS8+tHW7tZpMtjlNb7HKau0QDpwm49u0vUp9y1WOF+PEzkU84y9GqYaAVW8aH8f3GcBck26jh54cX4Q==",
+ "cpu": [
+ "ia32"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "win32"
+ ],
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/wrangler/node_modules/@esbuild/win32-x64": {
+ "version": "0.27.3",
+ "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.27.3.tgz",
+ "integrity": "sha512-4uJGhsxuptu3OcpVAzli+/gWusVGwZZHTlS63hh++ehExkVT8SgiEf7/uC/PclrPPkLhZqGgCTjd0VWLo6xMqA==",
+ "cpu": [
+ "x64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "win32"
+ ],
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/wrangler/node_modules/esbuild": {
+ "version": "0.27.3",
+ "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.27.3.tgz",
+ "integrity": "sha512-8VwMnyGCONIs6cWue2IdpHxHnAjzxnw2Zr7MkVxB2vjmQ2ivqGFb4LEG3SMnv0Gb2F/G/2yA8zUaiL1gywDCCg==",
+ "dev": true,
+ "hasInstallScript": true,
+ "license": "MIT",
+ "bin": {
+ "esbuild": "bin/esbuild"
+ },
+ "engines": {
+ "node": ">=18"
+ },
+ "optionalDependencies": {
+ "@esbuild/aix-ppc64": "0.27.3",
+ "@esbuild/android-arm": "0.27.3",
+ "@esbuild/android-arm64": "0.27.3",
+ "@esbuild/android-x64": "0.27.3",
+ "@esbuild/darwin-arm64": "0.27.3",
+ "@esbuild/darwin-x64": "0.27.3",
+ "@esbuild/freebsd-arm64": "0.27.3",
+ "@esbuild/freebsd-x64": "0.27.3",
+ "@esbuild/linux-arm": "0.27.3",
+ "@esbuild/linux-arm64": "0.27.3",
+ "@esbuild/linux-ia32": "0.27.3",
+ "@esbuild/linux-loong64": "0.27.3",
+ "@esbuild/linux-mips64el": "0.27.3",
+ "@esbuild/linux-ppc64": "0.27.3",
+ "@esbuild/linux-riscv64": "0.27.3",
+ "@esbuild/linux-s390x": "0.27.3",
+ "@esbuild/linux-x64": "0.27.3",
+ "@esbuild/netbsd-arm64": "0.27.3",
+ "@esbuild/netbsd-x64": "0.27.3",
+ "@esbuild/openbsd-arm64": "0.27.3",
+ "@esbuild/openbsd-x64": "0.27.3",
+ "@esbuild/openharmony-arm64": "0.27.3",
+ "@esbuild/sunos-x64": "0.27.3",
+ "@esbuild/win32-arm64": "0.27.3",
+ "@esbuild/win32-ia32": "0.27.3",
+ "@esbuild/win32-x64": "0.27.3"
+ }
+ },
+ "node_modules/ws": {
+ "version": "8.18.0",
+ "resolved": "https://registry.npmjs.org/ws/-/ws-8.18.0.tgz",
+ "integrity": "sha512-8VbfWfHLbbwu3+N6OKsOMpBdT4kXPDDB9cJk2bJ6mh9ucxdlnNvH1e+roYkKmN9Nxw2yjz7VzeO9oOz2zJ04Pw==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=10.0.0"
+ },
+ "peerDependencies": {
+ "bufferutil": "^4.0.1",
+ "utf-8-validate": ">=5.0.2"
+ },
+ "peerDependenciesMeta": {
+ "bufferutil": {
+ "optional": true
+ },
+ "utf-8-validate": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/yallist": {
+ "version": "3.1.1",
+ "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz",
+ "integrity": "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==",
+ "dev": true,
+ "license": "ISC"
+ },
+ "node_modules/yocto-queue": {
+ "version": "0.1.0",
+ "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz",
+ "integrity": "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=10"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/yoga-layout": {
+ "version": "3.2.1",
+ "resolved": "https://registry.npmjs.org/yoga-layout/-/yoga-layout-3.2.1.tgz",
+ "integrity": "sha512-0LPOt3AxKqMdFBZA3HBAt/t/8vIKq7VaQYbuA8WxCgung+p9TVyKRYdpvCb80HcdTN2NkbIKbhNwKUfm3tQywQ==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/youch": {
+ "version": "4.1.0-beta.10",
+ "resolved": "https://registry.npmjs.org/youch/-/youch-4.1.0-beta.10.tgz",
+ "integrity": "sha512-rLfVLB4FgQneDr0dv1oddCVZmKjcJ6yX6mS4pU82Mq/Dt9a3cLZQ62pDBL4AUO+uVrCvtWz3ZFUL2HFAFJ/BXQ==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@poppinss/colors": "^4.1.5",
+ "@poppinss/dumper": "^0.6.4",
+ "@speed-highlight/core": "^1.2.7",
+ "cookie": "^1.0.2",
+ "youch-core": "^0.3.3"
+ }
+ },
+ "node_modules/youch-core": {
+ "version": "0.3.3",
+ "resolved": "https://registry.npmjs.org/youch-core/-/youch-core-0.3.3.tgz",
+ "integrity": "sha512-ho7XuGjLaJ2hWHoK8yFnsUGy2Y5uDpqSTq1FkHLK4/oqKtyUU1AFbOOxY4IpC9f0fTLjwYbslUz0Po5BpD1wrA==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@poppinss/exception": "^1.2.2",
+ "error-stack-parser-es": "^1.0.5"
+ }
+ },
+ "node_modules/zod": {
+ "version": "4.4.3",
+ "resolved": "https://registry.npmjs.org/zod/-/zod-4.4.3.tgz",
+ "integrity": "sha512-ytENFjIJFl2UwYglde2jchW2Hwm4GJFLDiSXWdTrJQBIN9Fcyp7n4DhxJEiWNAJMV1/BqWfW/kkg71UDcHJyTQ==",
+ "dev": true,
+ "license": "MIT",
+ "funding": {
+ "url": "https://github.com/sponsors/colinhacks"
+ }
+ },
+ "node_modules/zod-validation-error": {
+ "version": "4.0.2",
+ "resolved": "https://registry.npmjs.org/zod-validation-error/-/zod-validation-error-4.0.2.tgz",
+ "integrity": "sha512-Q6/nZLe6jxuU80qb/4uJ4t5v2VEZ44lzQjPDhYJNztRQ4wyWc6VF3D3Kb/fAuPetZQnhS3hnajCf9CsWesghLQ==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=18.0.0"
+ },
+ "peerDependencies": {
+ "zod": "^3.25.0 || ^4.0.0"
+ }
+ }
+ }
+}
diff --git a/package.json b/package.json
new file mode 100644
index 0000000..7a1e492
--- /dev/null
+++ b/package.json
@@ -0,0 +1,45 @@
+{
+ "name": "site-creator-vinext-starter",
+ "version": "0.1.0",
+ "private": true,
+ "engines": {
+ "node": ">=22.13.0"
+ },
+ "scripts": {
+ "dev": "vinext dev",
+ "build": "vinext build",
+ "start": "vinext start",
+ "test": "npm run build && node --test tests/rendered-html.test.mjs",
+ "lint": "eslint . --ignore-pattern dist --ignore-pattern .next",
+ "db:generate": "drizzle-kit generate"
+ },
+ "dependencies": {
+ "drizzle-orm": "0.45.2",
+ "next": "16.2.12",
+ "react": "19.2.6",
+ "react-dom": "19.2.6"
+ },
+ "devDependencies": {
+ "@cloudflare/vite-plugin": "1.37.1",
+ "@tailwindcss/postcss": "4.2.1",
+ "@types/node": "22.19.19",
+ "@types/react": "19.2.14",
+ "@types/react-dom": "19.2.3",
+ "@vitejs/plugin-react": "6.0.2",
+ "@vitejs/plugin-rsc": "0.5.26",
+ "drizzle-kit": "0.31.10",
+ "eslint": "9.39.4",
+ "eslint-config-next": "16.2.12",
+ "react-server-dom-webpack": "19.2.6",
+ "tailwindcss": "4.2.1",
+ "typescript": "5.9.3",
+ "vinext": "0.0.50",
+ "vite": "8.0.13",
+ "wrangler": "4.92.0"
+ },
+ "overrides": {
+ "postcss": "8.5.25",
+ "sharp": "0.35.3"
+ },
+ "type": "module"
+}
diff --git a/postcss.config.mjs b/postcss.config.mjs
new file mode 100644
index 0000000..61e3684
--- /dev/null
+++ b/postcss.config.mjs
@@ -0,0 +1,7 @@
+const config = {
+ plugins: {
+ "@tailwindcss/postcss": {},
+ },
+};
+
+export default config;
diff --git a/public/favicon.svg b/public/favicon.svg
new file mode 100644
index 0000000..ca747cb
--- /dev/null
+++ b/public/favicon.svg
@@ -0,0 +1,6 @@
+
+
+
+
+
+
diff --git a/public/file.svg b/public/file.svg
new file mode 100644
index 0000000..004145c
--- /dev/null
+++ b/public/file.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/public/globe.svg b/public/globe.svg
new file mode 100644
index 0000000..567f17b
--- /dev/null
+++ b/public/globe.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/public/launch/2026-08-04-kian-pressure.png b/public/launch/2026-08-04-kian-pressure.png
new file mode 100644
index 0000000..2f4743d
Binary files /dev/null and b/public/launch/2026-08-04-kian-pressure.png differ
diff --git a/public/og-beta.png b/public/og-beta.png
new file mode 100644
index 0000000..e476814
Binary files /dev/null and b/public/og-beta.png differ
diff --git a/public/robots.txt b/public/robots.txt
new file mode 100644
index 0000000..46a9ebc
--- /dev/null
+++ b/public/robots.txt
@@ -0,0 +1,6 @@
+User-agent: *
+Allow: /
+Disallow: /admin
+Disallow: /api/
+
+Sitemap: https://www.debtworld.org/sitemap.xml
diff --git a/public/sitemap.xml b/public/sitemap.xml
new file mode 100644
index 0000000..67bcf8d
--- /dev/null
+++ b/public/sitemap.xml
@@ -0,0 +1,39 @@
+
+
+
+ https://www.debtworld.org/
+ 2026-08-01
+ weekly
+ 1.0
+
+
+ https://www.debtworld.org/en
+ 2026-08-01
+ weekly
+ 0.9
+
+
+ https://www.debtworld.org/about
+ 2026-08-01
+ monthly
+ 0.8
+
+
+ https://www.debtworld.org/en/about
+ 2026-08-01
+ monthly
+ 0.8
+
+
+ https://www.debtworld.org/safety
+ 2026-08-01
+ monthly
+ 0.7
+
+
+ https://www.debtworld.org/en/safety
+ 2026-08-01
+ monthly
+ 0.7
+
+
diff --git a/public/window.svg b/public/window.svg
new file mode 100644
index 0000000..b2b2a44
--- /dev/null
+++ b/public/window.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/tests/rendered-html.test.mjs b/tests/rendered-html.test.mjs
new file mode 100644
index 0000000..13317fd
--- /dev/null
+++ b/tests/rendered-html.test.mjs
@@ -0,0 +1,887 @@
+import assert from "node:assert/strict";
+import { readFile, readdir } from "node:fs/promises";
+import { fileURLToPath } from "node:url";
+import { dirname, resolve } from "node:path";
+import test, { after } from "node:test";
+import { Miniflare } from "miniflare";
+
+const testDirectory = dirname(fileURLToPath(import.meta.url));
+const serverDirectory = resolve(testDirectory, "../dist/server");
+const miniflare = new Miniflare({
+ modules: true,
+ scriptPath: resolve(serverDirectory, "index.js"),
+ modulesRoot: serverDirectory,
+ modulesRules: [{ type: "ESModule", include: ["**/*.js"] }],
+ compatibilityDate: "2026-05-22",
+ compatibilityFlags: ["nodejs_compat"],
+ d1Databases: { DB: "debt-world-test" },
+ bindings: {
+ OWNER_ADMIN_EMAIL: "owner@example.com",
+ COMMUNITY_ADMIN_EMAILS: "owner@example.com",
+ ACCOUNT_PASSWORD_ITERATIONS: "1000",
+ BETA_INVITES_REQUIRED: "true",
+ BETA_SIGNUPS_ENABLED: "true",
+ BETA_INVITE_CODE: "SHORE-TEST-2026",
+ BETA_INVITE_MAX_USES: "2",
+ },
+ serviceBindings: {
+ ASSETS: async () => new Response("Not found", { status: 404 }),
+ },
+});
+const testDb = await miniflare.getD1Database("DB");
+const migrationFiles = (await readdir(new URL("../drizzle/", import.meta.url)))
+ .filter((file) => file.endsWith(".sql"))
+ .sort();
+for (const migrationFile of migrationFiles) {
+ const migration = await readFile(new URL(`../drizzle/${migrationFile}`, import.meta.url), "utf8");
+ for (const statement of migration.split("--> statement-breakpoint").map((part) => part.trim()).filter(Boolean)) {
+ await testDb.prepare(statement).run();
+ }
+}
+after(() => miniflare.dispose());
+
+async function render(path = "/") {
+ return miniflare.dispatchFetch(`http://localhost${path}`, {
+ headers: { accept: "text/html" },
+ });
+}
+
+async function api(path, init = {}) {
+ const headers = new Headers(init.headers);
+ headers.set("accept", "application/json");
+ if (init.method && init.method !== "GET") {
+ headers.set("origin", "http://localhost");
+ }
+ return miniflare.dispatchFetch(`http://localhost${path}`, { ...init, headers });
+}
+
+test("server-renders the Chinese debt world", async () => {
+ const response = await render("/");
+ assert.equal(response.status, 200);
+ assert.match(response.headers.get("content-type") ?? "", /^text\/html\b/i);
+ const html = await response.text();
+ assert.match(html, /正在打开上岸星球/);
+ assert.doesNotMatch(html, /codex-preview|Your site is taking shape/i);
+});
+
+test("server-renders a complete English entry", async () => {
+ const response = await render("/en");
+ assert.equal(response.status, 200);
+ const html = await response.text();
+ assert.match(html, /Opening Debt World/);
+});
+
+test("server-renders bilingual safety centers with data controls", async () => {
+ const chinese = await render("/safety");
+ assert.equal(chinese.status, 200);
+ const chineseHtml = await chinese.text();
+ assert.match(chineseHtml, /数据与隐私说明/);
+ assert.match(chineseHtml, /怎样导出、撤回和删除/);
+ assert.match(chineseHtml, /社区参与限年满 18 岁/);
+ const english = await render("/en/safety");
+ assert.equal(english.status, 200);
+ const englishHtml = await english.text();
+ assert.match(englishHtml, /Data and privacy notice/);
+ assert.match(englishHtml, /How to export, withdraw, and delete/);
+ assert.match(englishHtml, /Community participation is for adults aged 18\+/);
+});
+
+test("server-renders bilingual contribution gateways with privacy boundaries", async () => {
+ const chinese = await render("/contribute");
+ assert.equal(chinese.status, 200);
+ const chineseHtml = await chinese.text();
+ assert.match(chineseHtml, /你不必会写代码/);
+ assert.match(chineseHtml, /这些内容不能进入公开仓库/);
+ assert.match(chineseHtml, /AGPL-3\.0/);
+ const english = await render("/en/contribute");
+ assert.equal(english.status, 200);
+ const englishHtml = await english.text();
+ assert.match(englishHtml, /You do not need to code/);
+ assert.match(englishHtml, /These never belong in the public repository/);
+});
+
+test("publishes indexable bilingual product pages and crawler routes", async () => {
+ const chineseAbout = await render("/about");
+ assert.equal(chineseAbout.status, 200);
+ assert.match(await chineseAbout.text(), /不是人均富豪的橱窗/);
+ const englishAbout = await render("/en/about");
+ assert.equal(englishAbout.status, 200);
+ assert.match(await englishAbout.text(), /Not another highlight reel/);
+ const robots = await render("/robots.txt");
+ assert.equal(robots.status, 200);
+ assert.match(await robots.text(), /sitemap\.xml/i);
+ const sitemap = await render("/sitemap.xml");
+ assert.equal(sitemap.status, 200);
+ const sitemapXml = await sitemap.text();
+ assert.match(sitemapXml, /\/en\/about/);
+ assert.match(sitemapXml, /\/en\/contribute/);
+});
+
+test("source includes real-date, multi-debt, voice, country currency, keyboard inspection, and a growing shared world", async () => {
+ const source = await readFile(new URL("../app/DebtWorldGame.tsx", import.meta.url), "utf8");
+ assert.match(source, /DebtKind/);
+ assert.match(source, /nextDueDate/);
+ assert.match(source, /confirmPayment/);
+ assert.match(source, /debt-world-v3/);
+ assert.match(source, /webkitSpeechRecognition/);
+ assert.match(source, /speechSynthesis/);
+ assert.match(source, /arrowup/);
+ assert.match(source, /mobile-controls/);
+ assert.match(source, /current\.map/);
+ assert.match(source, /\/api\/vault/);
+ assert.match(source, /WorldPulse/);
+ assert.match(source, /共同大世界正在生长/);
+ assert.doesNotMatch(source, /=\s*1_000/);
+ assert.match(source, /mbtiOptions/);
+ assert.match(source, /repaymentOutlook/);
+ assert.match(source, /SharedWalker/);
+ assert.match(source, /mobile-planner-sheet/);
+ assert.match(source, /真实共享角色/);
+ assert.match(source, /const SYSTEM_DEMO_COUNT = 30/);
+ assert.match(source, /source: "system_demo"/);
+ assert.match(source, /SYSTEM DEMO · FICTIONAL COMPOSITE/);
+ assert.match(source, /不计入上方真实统计/);
+ assert.match(source, /worldExpansionTier/);
+ assert.match(source, /world-expansion-\$\{worldExpansionTier\}/);
+ assert.match(source, /upcomingMissions/);
+ assert.match(source, /map-layer-switcher/);
+ assert.match(source, /map-mission/);
+ assert.match(source, /现实任务站/);
+ assert.match(source, /opening never marks paid/);
+ assert.match(source, /worldDayPhase/);
+ const demoRoster = source.match(/const demoNpcSeeds: DemoNpcSeed\[\] = \[[\s\S]*?\n\];/)?.[0] ?? "";
+ assert.equal((demoRoster.match(/\{ flag:/g) ?? []).length, 30);
+ assert.doesNotMatch(source, /value\s*>=\s*1_000_000|toFixed\(/);
+
+ const styles = await readFile(new URL("../app/globals.css", import.meta.url), "utf8");
+ assert.match(styles, /\.chat-bubble p[^}]*font-size:\s*14px/s);
+ assert.match(styles, /\.npc-portrait[^}]*width:\s*142px/s);
+ assert.match(styles, /Readability system/);
+ assert.match(styles, /Game-score numbers/);
+ assert.match(styles, /self-aura/);
+ assert.match(styles, /\.npc-tag[^}]*border-radius:\s*17px/s);
+ assert.match(styles, /light-tier-4/);
+ assert.match(styles, /light-arrival/);
+ assert.match(styles, /real-story-tag/);
+ assert.match(styles, /real-light-milestones/);
+ assert.match(styles, /\.world-canvas\.world-expansion-2/);
+ assert.match(styles, /\.demo-npc\.npc-near \.npc-tag/);
+ assert.match(styles, /\.demo-world-note/);
+ assert.match(styles, /\.map-layer-switcher/);
+ assert.match(styles, /\.map-mission/);
+ assert.match(styles, /\.mission-dock/);
+ assert.match(styles, /\.biome-lake/);
+ assert.match(styles, /@keyframes mission-ring/);
+ const communitySource = await readFile(new URL("../app/CommunityPanel.tsx", import.meta.url), "utf8");
+ assert.match(communitySource, /story-light-burst/);
+ assert.match(communitySource, /光已送达 \+1/);
+ assert.match(communitySource, /每日最多 3 次投稿、30 次送光和 10 次举报/);
+ assert.match(communitySource, /SAFETY_POLICY_VERSION/);
+ assert.match(communitySource, /delete_story/);
+ assert.match(communitySource, /mbtiDebt/);
+ const communityRoute = await readFile(new URL("../app/api/community/route.ts", import.meta.url), "utf8");
+ assert.match(communityRoute, /MIN_PROFILE_GROUP\s*=\s*5/);
+ assert.match(communityRoute, /profileVaults\.size\s*>=\s*MIN_AGGREGATE_SAMPLE/);
+ assert.match(communityRoute, /SELECT COUNT\(\*\) FROM vaults/);
+ assert.doesNotMatch(communityRoute, /system_demo|demoNpcSeeds|npcData/);
+ const adminSource = await readFile(new URL("../app/AdminCommunityPanel.tsx", import.meta.url), "utf8");
+ assert.match(adminSource, /真实世界安全审核台/);
+ assert.match(adminSource, /approve/);
+ assert.match(adminSource, /restore/);
+ const adminRoute = await readFile(new URL("../app/api/admin/community/route.ts", import.meta.url), "utf8");
+ assert.match(adminRoute, /community_moderation_actions/);
+ assert.match(adminRoute, /requireCommunityAdmin/);
+ const communitySafety = await readFile(new URL("../lib/community-safety.ts", import.meta.url), "utf8");
+ assert.match(communitySafety, /publish:\s*3/);
+ assert.match(communitySafety, /encourage:\s*30/);
+ assert.match(communitySafety, /report:\s*10/);
+ assert.match(communitySafety, /cleanModerationNote/);
+ const safetyCenter = await readFile(new URL("../app/SafetyCenter.tsx", import.meta.url), "utf8");
+ assert.match(safetyCenter, /Private by default/);
+ assert.match(safetyCenter, /Official principles used in product design/);
+ assert.match(styles, /special-payment-tools/);
+ assert.match(styles, /community-panel/);
+ assert.match(styles, /admin-community-panel/);
+ assert.match(styles, /safety-page/);
+ assert.match(styles, /policy-confirm/);
+ assert.match(styles, /beta-invite-entry/);
+ assert.match(styles, /feedback-panel/);
+ assert.match(styles, /beta-admin-panel/);
+ assert.match(styles, /account-shell/);
+ assert.match(styles, /owner-admin-shell/);
+
+ const accountGate = await readFile(new URL("../app/AccountGate.tsx", import.meta.url), "utf8");
+ assert.match(accountGate, /注册新账号/);
+ assert.match(accountGate, /没有保险箱、恢复码或手动同步步骤/);
+ const accountServer = await readFile(new URL("../lib/account-server.ts", import.meta.url), "utf8");
+ assert.match(accountServer, /PBKDF2/);
+ assert.match(accountServer, /MAX_PASSWORD_ITERATIONS\s*=\s*100_000/);
+ assert.match(accountServer, /HttpOnly/);
+ assert.match(accountServer, /account_auth_limits/);
+ const ownerDashboard = await readFile(new URL("../app/OwnerAdminDashboard.tsx", import.meta.url), "utf8");
+ assert.match(ownerDashboard, /唯一管理员/);
+ assert.match(ownerDashboard, /内测反馈/);
+
+ const betaServer = await readFile(new URL("../lib/beta-server.ts", import.meta.url), "utf8");
+ assert.match(betaServer, /constantEqual/);
+ assert.match(betaServer, /BETA_INVITE_MAX_USES/);
+ assert.doesNotMatch(betaServer, /console\.(log|error)/);
+
+ const ratesRoute = await readFile(new URL("../app/api/rates/route.ts", import.meta.url), "utf8");
+ assert.match(ratesRoute, /api\.frankfurter\.dev\/v2\/rates/);
+ assert.match(ratesRoute, /fallbackUsdRates/);
+ const advisorServer = await readFile(new URL("../lib/advisor-server.ts", import.meta.url), "utf8");
+ assert.match(advisorServer, /gpt-5\.6-terra/);
+ assert.match(advisorServer, /MiniMax-M2\.7/);
+ assert.match(advisorServer, /api\.minimaxi\.com\/v1/);
+ assert.match(advisorServer, /MINIMAX_API_KEY/);
+ assert.match(advisorServer, /process\.env/);
+ assert.match(advisorServer, /store:\s*false/);
+ assert.match(advisorServer, /safety_identifier/);
+ assert.match(advisorServer, /ADVISOR_DAILY_REQUEST_LIMIT\s*=\s*20/);
+ assert.match(advisorServer, /ai_daily_usage/);
+ assert.match(advisorServer, /minimum_payment/);
+ assert.match(advisorServer, /highest APR first/);
+ assert.doesNotMatch(advisorServer, /console\.(log|error)/);
+});
+
+test("an account automatically enters, persists, exports, and deletes a debt journey", async () => {
+ await testDb.prepare("DROP TABLE account_auth_limits").run();
+ await testDb.prepare("DROP TABLE account_sessions").run();
+ await testDb.prepare("DROP TABLE account_vaults").run();
+ await testDb.prepare("ALTER TABLE accounts DROP COLUMN signup_source").run();
+ await testDb.prepare("DROP TABLE payment_records").run();
+ await testDb.prepare("DROP TABLE policy_acceptances").run();
+ await testDb.prepare("DROP TABLE beta_enrollments").run();
+ await testDb.prepare("DROP TABLE beta_feedback").run();
+ await testDb.prepare("ALTER TABLE vaults DROP COLUMN age_band").run();
+ await testDb.prepare("ALTER TABLE debts DROP COLUMN apr").run();
+ const betaState = await api("/api/beta");
+ assert.equal(betaState.status, 200);
+ assert.deepEqual(await betaState.json(), { signupsEnabled: true, accountSignupsEnabled: true, inviteRequired: true, ready: true });
+
+ const weakAccount = await api("/api/account", {
+ method: "POST",
+ headers: { "content-type": "application/json" },
+ body: JSON.stringify({ action: "register", username: "walker-one", password: "short" }),
+ });
+ assert.equal(weakAccount.status, 400);
+
+ const accountCreate = await api("/api/account", {
+ method: "POST",
+ headers: { "content-type": "application/json" },
+ body: JSON.stringify({ action: "register", username: "walker-one", password: "safe-password-2026", signupSource: "github" }),
+ });
+ assert.equal(accountCreate.status, 201);
+ const accountCreated = await accountCreate.json();
+ assert.equal(accountCreated.authenticated, true);
+ assert.match(accountCreated.account.userCode, /^SHORE-/);
+ assert.equal(accountCreated.account.vaultLinked, true);
+ const accountColumns = await testDb.prepare("PRAGMA table_info(accounts)").all();
+ assert.equal(accountColumns.results.some((column) => column.name === "signup_source"), true);
+ const cookie = accountCreate.headers.get("set-cookie")?.split(";")[0];
+ assert.match(cookie ?? "", /^dw_account=/);
+
+ const duplicateAccount = await api("/api/account", {
+ method: "POST",
+ headers: { "content-type": "application/json" },
+ body: JSON.stringify({ action: "register", username: "WALKER-ONE", password: "safe-password-2027" }),
+ });
+ assert.equal(duplicateAccount.status, 409);
+
+ const automaticWorld = await api("/api/vault", { headers: { cookie } });
+ assert.equal(automaticWorld.status, 200);
+ assert.equal((await automaticWorld.json()).vault.debts.length, 0);
+
+ const profileUpdate = await api("/api/vault", {
+ method: "PATCH",
+ headers: { "content-type": "application/json", cookie },
+ body: JSON.stringify({
+ locale: "zh",
+ profile: {
+ alias: "测试行者", region: "亚洲", pressure: "现金流压力", countryCode: "CN", countryName: "", displayCurrency: "CNY", monthlyIncome: 30_000, monthlyExpenses: 9_000,
+ ageBand: "25-34", gender: "prefer_not_say", mbti: "INFP", zodiac: "virgo", selfDescription: "房贷和生活开销叠在一起。", repaymentPlan: "保留生活缓冲后按月还款。", repaymentOutlook: "trying", incomePlan: "尝试增加自由职业收入。",
+ },
+ position: { x: 48, y: 62 },
+ discoveryConsent: true,
+ }),
+ });
+ assert.equal(profileUpdate.status, 200);
+
+ const accountAfterVault = await api("/api/account", { headers: { cookie } });
+ assert.equal(accountAfterVault.status, 200);
+ assert.equal((await accountAfterVault.json()).account.vaultLinked, true);
+
+ const advisorWithoutVault = await api("/api/advisor", {
+ method: "POST",
+ headers: { "content-type": "application/json" },
+ body: JSON.stringify({ message: "帮我拆解债务", locale: "zh" }),
+ });
+ assert.equal(advisorWithoutVault.status, 401);
+
+ const advisorReadiness = await api("/api/advisor");
+ assert.equal(advisorReadiness.status, 200);
+ assert.deepEqual(await advisorReadiness.json(), {
+ configured: false,
+ provider: null,
+ model: null,
+ });
+
+ const advisorWithoutServerKey = await api("/api/advisor", {
+ method: "POST",
+ headers: { "content-type": "application/json", cookie },
+ body: JSON.stringify({ message: "帮我拆解债务", locale: "zh" }),
+ });
+ assert.equal(advisorWithoutServerKey.status, 503);
+
+ const anonymousRead = await api("/api/vault");
+ assert.equal(anonymousRead.status, 401);
+
+ const debtCreate = await api("/api/debts", {
+ method: "POST",
+ headers: { "content-type": "application/json", cookie },
+ body: JSON.stringify({
+ id: "demo-card",
+ kind: "other",
+ customLabel: "欠朋友的钱",
+ currency: "CNY",
+ original: 4_000_000,
+ balance: 4_000_000,
+ monthly: 13_000,
+ apr: 3.85,
+ minimumPayment: 13_000,
+ paymentStatus: "current",
+ remainingMonths: 312,
+ dueDay: 15,
+ method: "银行卡自动扣款",
+ }),
+ });
+ assert.equal(debtCreate.status, 201);
+ const debt = (await debtCreate.json()).debt;
+ assert.notEqual(debt.id, "demo-card");
+ assert.equal(debt.sharingMode, "private");
+
+ const sharingUpdate = await api("/api/debts", {
+ method: "PATCH",
+ headers: { "content-type": "application/json", cookie },
+ body: JSON.stringify({ id: debt.id, sharingMode: "range" }),
+ });
+ assert.equal(sharingUpdate.status, 200);
+
+ const paymentCreate = await api("/api/payments", {
+ method: "POST",
+ headers: { "content-type": "application/json", cookie },
+ body: JSON.stringify({
+ debtId: debt.id,
+ cashPayment: 13_000,
+ newBalance: 3_998_500,
+ scheduledDate: "2026-07-15",
+ }),
+ });
+ assert.equal(paymentCreate.status, 201);
+
+ const prepayment = await api("/api/payments", {
+ method: "POST",
+ headers: { "content-type": "application/json", cookie },
+ body: JSON.stringify({ debtId: debt.id, cashPayment: 2_000, newBalance: 3_997_200, source: "prepayment", timezoneOffset: -480 }),
+ });
+ assert.equal(prepayment.status, 201);
+ assert.equal((await prepayment.json()).payment.source, "prepayment");
+
+ const luckyIncome = await api("/api/payments", {
+ method: "POST",
+ headers: { "content-type": "application/json", cookie },
+ body: JSON.stringify({ debtId: debt.id, cashPayment: 500, newBalance: 3_996_800, source: "lucky_income", incomeType: "freelance", timezoneOffset: -480 }),
+ });
+ assert.equal(luckyIncome.status, 201);
+ assert.equal((await luckyIncome.json()).payment.incomeType, "freelance");
+
+ const duplicateLuckyIncome = await api("/api/payments", {
+ method: "POST",
+ headers: { "content-type": "application/json", cookie },
+ body: JSON.stringify({ debtId: debt.id, cashPayment: 100, newBalance: 3_996_700, source: "lucky_income", incomeType: "refund", timezoneOffset: -480 }),
+ });
+ assert.equal(duplicateLuckyIncome.status, 409);
+
+ const missingPolicyStory = await api("/api/community", {
+ method: "POST",
+ headers: { "content-type": "application/json", cookie },
+ body: JSON.stringify({ action: "publish", debtId: debt.id, repaymentApproach: "extra_income", storyText: "我正在用额外收入慢慢还款,联系电话 13800138000,原来欠款 4000000。" }),
+ });
+ assert.equal(missingPolicyStory.status, 428);
+
+ const storyCreate = await api("/api/community", {
+ method: "POST",
+ headers: { "content-type": "application/json", cookie },
+ body: JSON.stringify({ action: "publish", debtId: debt.id, repaymentApproach: "extra_income", storyText: "我正在用额外收入慢慢还款,联系电话 13800138000,原来欠款 4000000。", rulesAccepted: true, ageConfirmed: true }),
+ });
+ assert.equal(storyCreate.status, 201);
+ assert.equal((await storyCreate.json()).redacted, true);
+
+ const ownerCommunity = await api("/api/community", { headers: { cookie } });
+ assert.equal(ownerCommunity.status, 200);
+ const ownerCommunityBody = await ownerCommunity.json();
+ assert.equal(ownerCommunityBody.stories.length, 0);
+ assert.equal(ownerCommunityBody.mine.length, 1);
+ assert.match(ownerCommunityBody.mine[0].storyText, /private detail hidden/);
+ assert.doesNotMatch(ownerCommunityBody.mine[0].amountBand, /3,996,800/);
+ assert.equal(ownerCommunityBody.insights.ready, false);
+ assert.equal(ownerCommunityBody.policy.accepted, true);
+ assert.equal(ownerCommunityBody.worldPulse.population, 1);
+ assert.equal(ownerCommunityBody.worldPulse.recordedDebts, 1);
+ assert.equal(ownerCommunityBody.worldPulse.confirmedPayments, 3);
+ assert.equal(ownerCommunityBody.worldPulse.countries, 1);
+ assert.equal(ownerCommunityBody.sharedWalkers.length, 1);
+ assert.equal(ownerCommunityBody.sharedWalkers[0].isMine, true);
+ assert.equal(ownerCommunityBody.sharedWalkers[0].debtCountBand, "single");
+ assert.equal(ownerCommunityBody.sharedWalkers[0].primaryDebtKind, "other");
+ assert.ok(!("balance" in ownerCommunityBody.sharedWalkers[0]));
+ assert.ok(!("original" in ownerCommunityBody.sharedWalkers[0]));
+ assert.ok(!("customLabel" in ownerCommunityBody.sharedWalkers[0]));
+
+ const anonymousCommunity = await api("/api/community");
+ assert.equal(anonymousCommunity.status, 200);
+ const anonymousCommunityBody = await anonymousCommunity.json();
+ assert.equal(anonymousCommunityBody.mine.length, 0);
+ assert.equal(anonymousCommunityBody.sharedWalkers.length, 1);
+ assert.equal(anonymousCommunityBody.sharedWalkers[0].isMine, false);
+ assert.ok(!("debtCount" in anonymousCommunityBody.sharedWalkers[0]));
+
+ const unauthorizedAdmin = await api("/api/admin/community?summary=1");
+ assert.equal(unauthorizedAdmin.status, 404);
+ const adminHeaders = { "oai-authenticated-user-email": "owner@example.com" };
+ const ownerHeaders = { ...adminHeaders, cookie };
+ const ownerWithoutSiteAccount = await api("/api/admin/session", { headers: adminHeaders });
+ assert.equal(ownerWithoutSiteAccount.status, 401);
+ const siteAccountWithoutOwner = await api("/api/admin/session", { headers: { cookie } });
+ assert.equal(siteAccountWithoutOwner.status, 404);
+ const ownerSessionBefore = await api("/api/admin/session", { headers: ownerHeaders });
+ assert.equal(ownerSessionBefore.status, 200);
+ assert.equal((await ownerSessionBefore.json()).registered, false);
+ const betaBeforeActivation = await api("/api/admin/beta", { headers: ownerHeaders });
+ assert.equal(betaBeforeActivation.status, 404);
+ const wrongOwnerActivation = await api("/api/admin/session", {
+ method: "POST",
+ headers: { "content-type": "application/json", "oai-authenticated-user-email": "other@example.com", cookie },
+ body: JSON.stringify({ action: "register" }),
+ });
+ assert.equal(wrongOwnerActivation.status, 404);
+ const ownerActivation = await api("/api/admin/session", {
+ method: "POST",
+ headers: { "content-type": "application/json", ...ownerHeaders },
+ body: JSON.stringify({ action: "register" }),
+ });
+ assert.equal(ownerActivation.status, 201);
+ const ownerActivationBody = await ownerActivation.json();
+ assert.equal(ownerActivationBody.registered, true);
+ assert.equal(ownerActivationBody.accountUsername, "walker-one");
+ assert.equal(ownerActivationBody.accountCode, accountCreated.account.userCode);
+ const firstTraffic = await api("/api/analytics", {
+ method: "POST",
+ headers: { "content-type": "application/json" },
+ body: JSON.stringify({ locale: "zh", path: "/", source: "github" }),
+ });
+ assert.equal(firstTraffic.status, 200);
+ const visitorCookie = firstTraffic.headers.get("set-cookie")?.split(";")[0];
+ assert.match(visitorCookie ?? "", /^dw_visitor=/);
+ const repeatedTraffic = await api("/api/analytics", {
+ method: "POST",
+ headers: { "content-type": "application/json", cookie: visitorCookie },
+ body: JSON.stringify({ locale: "zh", path: "/", source: "github" }),
+ });
+ assert.equal(repeatedTraffic.status, 200);
+ const betaAdmin = await api("/api/admin/beta", { headers: ownerHeaders });
+ assert.equal(betaAdmin.status, 200);
+ const betaAdminBody = await betaAdmin.json();
+ assert.equal(betaAdminBody.counts.enrolled, 0);
+ assert.equal(betaAdminBody.counts.accounts, 1);
+ assert.equal(betaAdminBody.testers[0].username, "walker-one");
+ assert.equal(betaAdminBody.testers[0].signupSource, "github");
+ assert.equal(betaAdminBody.testers[0].debtCount, 1);
+ assert.equal(betaAdminBody.counts.visitorsToday, 1);
+ assert.equal(betaAdminBody.counts.pageViewsToday, 2);
+ assert.equal(betaAdminBody.trafficDaily.at(-1).uniqueVisitors, 1);
+ assert.deepEqual(betaAdminBody.sources, [{ source: "github", accounts: 1, linked: 1, withDebt: 1, withFeedback: 0 }]);
+ assert.doesNotMatch(JSON.stringify(betaAdminBody), /测试行者|3996800|safe-password|recovery/i);
+
+ const feedbackCreate = await api("/api/beta/feedback", {
+ method: "POST",
+ headers: { "content-type": "application/json", cookie },
+ body: JSON.stringify({ category: "confusing", rating: 3, message: "最低还款和计划月还的区别需要更明显。", pagePath: "/?private=1" }),
+ });
+ assert.equal(feedbackCreate.status, 201);
+ const feedbackId = (await feedbackCreate.json()).id;
+
+ const feedbackAdmin = await api("/api/admin/beta", { headers: ownerHeaders });
+ const feedbackAdminBody = await feedbackAdmin.json();
+ assert.equal(feedbackAdminBody.feedback[0].testerCode, accountCreated.account.userCode);
+ assert.equal(feedbackAdminBody.feedback[0].username, "walker-one");
+ assert.equal(feedbackAdminBody.sources[0].withFeedback, 1);
+
+ const referralState = await api("/api/referral", { headers: { cookie } });
+ assert.equal(referralState.status, 200);
+ const referralCode = (await referralState.json()).referral.code;
+ assert.match(referralCode, /^SHORE-/);
+ const secondAccount = await api("/api/account", {
+ method: "POST",
+ headers: { "content-type": "application/json" },
+ body: JSON.stringify({ action: "register", username: "walker-two", password: "another-safe-2026", signupSource: "referral", referralCode }),
+ });
+ assert.equal(secondAccount.status, 201);
+ const secondAccountBody = await secondAccount.clone().json();
+ const secondCookie = secondAccount.headers.get("set-cookie")?.split(";")[0];
+ assert.match(secondCookie ?? "", /^dw_account=/);
+ const secondAccountOwnerAttempt = await api("/api/admin/session", {
+ headers: { ...adminHeaders, cookie: secondCookie },
+ });
+ assert.equal(secondAccountOwnerAttempt.status, 404);
+
+ const pauseSignups = await api("/api/admin/beta", {
+ method: "POST",
+ headers: { "content-type": "application/json", ...ownerHeaders },
+ body: JSON.stringify({ action: "set_signups", enabled: false }),
+ });
+ assert.equal(pauseSignups.status, 200);
+ assert.equal((await pauseSignups.json()).config.signupsEnabled, false);
+ const pausedAttempt = await api("/api/account", {
+ method: "POST",
+ headers: { "content-type": "application/json" },
+ body: JSON.stringify({ action: "register", username: "paused-walker", password: "paused-safe-password-2026" }),
+ });
+ assert.equal(pausedAttempt.status, 503);
+ const resumeSignups = await api("/api/admin/beta", {
+ method: "POST",
+ headers: { "content-type": "application/json", ...ownerHeaders },
+ body: JSON.stringify({ action: "set_signups", enabled: true }),
+ });
+ assert.equal(resumeSignups.status, 200);
+
+ const resolveFeedback = await api("/api/admin/beta", {
+ method: "POST",
+ headers: { "content-type": "application/json", ...ownerHeaders },
+ body: JSON.stringify({ action: "resolve_feedback", feedbackId }),
+ });
+ assert.equal(resolveFeedback.status, 200);
+ assert.equal((await resolveFeedback.json()).counts.openFeedback, 0);
+ const reopenFeedback = await api("/api/admin/beta", {
+ method: "POST",
+ headers: { "content-type": "application/json", ...ownerHeaders },
+ body: JSON.stringify({ action: "reopen_feedback", feedbackId }),
+ });
+ assert.equal(reopenFeedback.status, 200);
+ assert.equal((await reopenFeedback.json()).counts.openFeedback, 1);
+ const resolveFeedbackAgain = await api("/api/admin/beta", {
+ method: "POST",
+ headers: { "content-type": "application/json", ...ownerHeaders },
+ body: JSON.stringify({ action: "resolve_feedback", feedbackId }),
+ });
+ assert.equal(resolveFeedbackAgain.status, 200);
+
+ const moderationQueue = await api("/api/admin/community", { headers: ownerHeaders });
+ assert.equal(moderationQueue.status, 200);
+ const moderationQueueBody = await moderationQueue.json();
+ assert.equal(moderationQueueBody.counts.pending, 1);
+ assert.equal(moderationQueueBody.stories[0].storyText, ownerCommunityBody.mine[0].storyText);
+
+ const publishedStoryId = ownerCommunityBody.mine[0].id;
+ const approval = await api("/api/admin/community", {
+ method: "POST",
+ headers: { "content-type": "application/json", ...ownerHeaders },
+ body: JSON.stringify({ storyId: publishedStoryId, action: "approve" }),
+ });
+ assert.equal(approval.status, 200);
+ assert.equal((await approval.json()).status, "published");
+
+ const secondVault = await api("/api/vault", {
+ method: "PATCH",
+ headers: { "content-type": "application/json", cookie: secondCookie },
+ body: JSON.stringify({ locale: "en", profile: { alias: "Second walker", region: "Private", countryCode: "US", displayCurrency: "USD" } }),
+ });
+ assert.equal(secondVault.status, 200);
+ const invitedDebt = await api("/api/debts", {
+ method: "POST",
+ headers: { "content-type": "application/json", cookie: secondCookie },
+ body: JSON.stringify({ kind: "card", currency: "USD", original: 1200, balance: 1200, monthly: 100, apr: 18, minimumPayment: 50, paymentStatus: "current", remainingMonths: 14, dueDay: 5, method: "autopay" }),
+ });
+ assert.equal(invitedDebt.status, 201);
+ assert.equal((await invitedDebt.json()).referralActivated, true);
+ const rewardedReferralState = await api("/api/referral", { headers: { cookie } });
+ const rewardedReferral = (await rewardedReferralState.json()).referral;
+ assert.equal(rewardedReferral.invited, 1);
+ assert.equal(rewardedReferral.activated, 1);
+ const referralAdmin = await api("/api/admin/beta", { headers: ownerHeaders });
+ const referralAdminBody = await referralAdmin.json();
+ assert.equal(referralAdminBody.counts.referralInvites, 1);
+ assert.equal(referralAdminBody.counts.referralActivated, 1);
+ assert.equal(referralAdminBody.counts.referralPending, 0);
+ const thirdAccount = await api("/api/account", {
+ method: "POST",
+ headers: { "content-type": "application/json" },
+ body: JSON.stringify({ action: "register", username: "walker-three", password: "third-safe-password-2026" }),
+ });
+ assert.equal(thirdAccount.status, 201);
+ const thirdCookie = thirdAccount.headers.get("set-cookie")?.split(";")[0];
+ const thirdWorld = await api("/api/vault", { headers: { cookie: thirdCookie } });
+ assert.equal(thirdWorld.status, 200);
+
+ const secondCommunity = await api("/api/community", { headers: { cookie: secondCookie } });
+ assert.equal(secondCommunity.status, 200);
+ const secondCommunityBody = await secondCommunity.json();
+ assert.equal(secondCommunityBody.stories.length, 1);
+ assert.equal(secondCommunityBody.stories[0].id, publishedStoryId);
+ assert.equal(secondCommunityBody.stories[0].encouraged, false);
+ assert.equal(secondCommunityBody.stories[0].encouragementCount, 0);
+ assert.doesNotMatch(secondCommunityBody.stories[0].amountBand, /3,996,800/);
+
+ const encouragement = await api("/api/community", {
+ method: "POST",
+ headers: { "content-type": "application/json", cookie: secondCookie },
+ body: JSON.stringify({ action: "encourage", storyId: publishedStoryId }),
+ });
+ assert.equal(encouragement.status, 200);
+ assert.deepEqual(await encouragement.json(), { encouraged: true, count: 1 });
+
+ const secondVaultRow = await testDb.prepare(
+ "SELECT id FROM vaults WHERE alias = 'Second walker' LIMIT 1",
+ ).first();
+ assert.ok(secondVaultRow?.id);
+ await testDb.prepare(
+ "UPDATE community_rate_limits SET count = 30 WHERE vault_id = ?1 AND action = 'encourage'",
+ ).bind(secondVaultRow.id).run();
+ await testDb.prepare(
+ "DELETE FROM story_encouragements WHERE story_id = ?1 AND vault_id = ?2",
+ ).bind(publishedStoryId, secondVaultRow.id).run();
+ const limitedEncouragement = await api("/api/community", {
+ method: "POST",
+ headers: { "content-type": "application/json", cookie: secondCookie },
+ body: JSON.stringify({ action: "encourage", storyId: publishedStoryId }),
+ });
+ assert.equal(limitedEncouragement.status, 429);
+ await testDb.prepare(
+ "UPDATE community_rate_limits SET count = 29 WHERE vault_id = ?1 AND action = 'encourage'",
+ ).bind(secondVaultRow.id).run();
+ const finalAllowedEncouragement = await api("/api/community", {
+ method: "POST",
+ headers: { "content-type": "application/json", cookie: secondCookie },
+ body: JSON.stringify({ action: "encourage", storyId: publishedStoryId }),
+ });
+ assert.equal(finalAllowedEncouragement.status, 200);
+ assert.deepEqual(await finalAllowedEncouragement.json(), { encouraged: true, count: 1 });
+
+ const duplicateEncouragement = await api("/api/community", {
+ method: "POST",
+ headers: { "content-type": "application/json", cookie: secondCookie },
+ body: JSON.stringify({ action: "encourage", storyId: publishedStoryId }),
+ });
+ assert.equal(duplicateEncouragement.status, 200);
+ assert.deepEqual(await duplicateEncouragement.json(), { encouraged: true, count: 1 });
+
+ const encouragedCommunity = await api("/api/community", { headers: { cookie: secondCookie } });
+ const encouragedCommunityBody = await encouragedCommunity.json();
+ assert.equal(encouragedCommunityBody.stories[0].encouraged, true);
+ assert.equal(encouragedCommunityBody.stories[0].encouragementCount, 1);
+
+ const windowKey = new Date().toISOString().slice(0, 10);
+ await testDb.prepare(
+ `INSERT INTO community_rate_limits (id, vault_id, action, window_key, count)
+ VALUES ('report-limit-test', ?1, 'report', ?2, 10)`,
+ ).bind(secondVaultRow.id, windowKey).run();
+ const limitedReport = await api("/api/community", {
+ method: "POST",
+ headers: { "content-type": "application/json", cookie: secondCookie },
+ body: JSON.stringify({ action: "report", storyId: publishedStoryId, reason: "identity_exposure", details: "Possible identity clue" }),
+ });
+ assert.equal(limitedReport.status, 429);
+ await testDb.prepare(
+ "UPDATE community_rate_limits SET count = 9 WHERE id = 'report-limit-test'",
+ ).run();
+ const highRiskReport = await api("/api/community", {
+ method: "POST",
+ headers: { "content-type": "application/json", cookie: secondCookie },
+ body: JSON.stringify({ action: "report", storyId: publishedStoryId, reason: "identity_exposure", details: "Possible identity clue" }),
+ });
+ assert.equal(highRiskReport.status, 200);
+ const hiddenFromWorld = await api("/api/community");
+ assert.equal((await hiddenFromWorld.json()).stories.length, 0);
+
+ const reportedQueue = await api("/api/admin/community", { headers: ownerHeaders });
+ const reportedQueueBody = await reportedQueue.json();
+ assert.equal(reportedQueueBody.counts.review, 1);
+ assert.equal(reportedQueueBody.counts.openReports, 1);
+ const missingHideReason = await api("/api/admin/community", {
+ method: "POST",
+ headers: { "content-type": "application/json", ...ownerHeaders },
+ body: JSON.stringify({ storyId: publishedStoryId, action: "hide" }),
+ });
+ assert.equal(missingHideReason.status, 400);
+ const hideStory = await api("/api/admin/community", {
+ method: "POST",
+ headers: { "content-type": "application/json", ...ownerHeaders },
+ body: JSON.stringify({ storyId: publishedStoryId, action: "hide", note: "Identity risk confirmed 4000000 owner@example.com" }),
+ });
+ assert.equal(hideStory.status, 200);
+ assert.equal((await hideStory.json()).status, "hidden");
+ const restoreStory = await api("/api/admin/community", {
+ method: "POST",
+ headers: { "content-type": "application/json", ...ownerHeaders },
+ body: JSON.stringify({ storyId: publishedStoryId, action: "restore", note: "Safe after review" }),
+ });
+ assert.equal(restoreStory.status, 200);
+ const resolvedQueue = await api("/api/admin/community", { headers: ownerHeaders });
+ const resolvedQueueBody = await resolvedQueue.json();
+ assert.equal(resolvedQueueBody.counts.openReports, 0);
+ assert.equal(resolvedQueueBody.actions.length, 3);
+ assert.doesNotMatch(JSON.stringify(resolvedQueueBody.actions), /4000000|owner@example\.com/);
+
+ const ownEncouragement = await api("/api/community", {
+ method: "POST",
+ headers: { "content-type": "application/json", cookie },
+ body: JSON.stringify({ action: "encourage", storyId: publishedStoryId }),
+ });
+ assert.equal(ownEncouragement.status, 400);
+
+ const deleteOwnStory = await api("/api/community", {
+ method: "POST",
+ headers: { "content-type": "application/json", cookie },
+ body: JSON.stringify({ action: "delete_story", storyId: publishedStoryId }),
+ });
+ assert.equal(deleteOwnStory.status, 200);
+ assert.equal((await deleteOwnStory.json()).deleted, true);
+ const afterStoryDeletion = await api("/api/community", { headers: { cookie } });
+ const afterStoryDeletionBody = await afterStoryDeletion.json();
+ assert.equal(afterStoryDeletionBody.stories.length, 0);
+ assert.equal(afterStoryDeletionBody.mine.length, 0);
+
+ const foreignPayment = await api("/api/payments", {
+ method: "POST",
+ headers: { "content-type": "application/json", cookie: secondCookie },
+ body: JSON.stringify({ debtId: debt.id, cashPayment: 1, newBalance: 1, source: "prepayment" }),
+ });
+ assert.equal(foreignPayment.status, 404);
+ const foreignStory = await api("/api/community", {
+ method: "POST",
+ headers: { "content-type": "application/json", cookie: secondCookie },
+ body: JSON.stringify({ action: "publish", debtId: debt.id, repaymentApproach: "other", storyText: "This is long enough but must not access another vault debt." }),
+ });
+ assert.equal(foreignStory.status, 404);
+ const suspendSecondAccount = await api("/api/admin/beta", {
+ method: "POST",
+ headers: { "content-type": "application/json", ...ownerHeaders },
+ body: JSON.stringify({ action: "set_account_status", testerCode: secondAccountBody.account.userCode, accountStatus: "suspended" }),
+ });
+ assert.equal(suspendSecondAccount.status, 200);
+ assert.equal((await suspendSecondAccount.json()).counts.suspendedAccounts, 1);
+ const suspendedSession = await api("/api/account", { headers: { cookie: secondCookie } });
+ assert.equal((await suspendedSession.json()).authenticated, false);
+ const reactivateSecondAccount = await api("/api/admin/beta", {
+ method: "POST",
+ headers: { "content-type": "application/json", ...ownerHeaders },
+ body: JSON.stringify({ action: "set_account_status", testerCode: secondAccountBody.account.userCode, accountStatus: "active" }),
+ });
+ assert.equal(reactivateSecondAccount.status, 200);
+ const reactivatedLogin = await api("/api/account", {
+ method: "POST",
+ headers: { "content-type": "application/json" },
+ body: JSON.stringify({ action: "login", username: "walker-two", password: "another-safe-2026" }),
+ });
+ assert.equal(reactivatedLogin.status, 200);
+
+ const exportResponse = await api("/api/vault?download=1", {
+ headers: { cookie },
+ });
+ assert.equal(exportResponse.status, 200);
+ assert.match(exportResponse.headers.get("content-disposition") ?? "", /attachment/);
+ const exported = await exportResponse.json();
+ assert.equal(exported.profile.alias, "测试行者");
+ assert.equal(exported.profile.countryCode, "CN");
+ assert.equal(exported.profile.displayCurrency, "CNY");
+ assert.equal(exported.profile.monthlyIncome, 30_000);
+ assert.equal(exported.profile.monthlyExpenses, 9_000);
+ assert.equal(exported.profile.ageBand, "25-34");
+ assert.equal(exported.profile.gender, "prefer_not_say");
+ assert.equal(exported.profile.mbti, "INFP");
+ assert.equal(exported.profile.zodiac, "virgo");
+ assert.equal(exported.profile.selfDescription, "房贷和生活开销叠在一起。");
+ assert.equal(exported.profile.repaymentPlan, "保留生活缓冲后按月还款。");
+ assert.equal(exported.profile.repaymentOutlook, "trying");
+ assert.equal(exported.profile.incomePlan, "尝试增加自由职业收入。");
+ assert.equal(exported.discoveryConsent, true);
+ assert.equal(exported.debts.length, 1);
+ assert.equal(exported.debts[0].customLabel, "欠朋友的钱");
+ assert.equal(exported.debts[0].sharingMode, "range");
+ assert.equal(exported.debts[0].apr, 3.85);
+ assert.equal(exported.debts[0].minimumPayment, 13_000);
+ assert.equal(exported.debts[0].paymentStatus, "current");
+ assert.equal(exported.debts[0].remainingMonths, 312);
+ assert.equal(exported.debts[0].balance, 3_996_800);
+ assert.equal(exported.debts[0].history.length, 3);
+ assert.equal(exported.debts[0].history[1].source, "prepayment");
+ assert.equal(exported.debts[0].history[2].source, "lucky_income");
+ assert.equal(exported.betaEnrollment, null);
+ assert.equal(exported.betaFeedback.length, 1);
+ assert.equal(exported.betaFeedback[0].category, "confusing");
+ assert.equal(exported.betaFeedback[0].status, "resolved");
+ assert.equal(exported.betaFeedback[0].pagePath, "/");
+ assert.equal(exported.policyAcceptances.length, 2);
+ assert.deepEqual(new Set(exported.policyAcceptances.map((item) => item.policyKey)), new Set(["community-rules-and-privacy", "community-age-18"]));
+
+ const deletion = await api("/api/vault", {
+ method: "DELETE",
+ headers: { "content-type": "application/json", cookie },
+ body: JSON.stringify({ confirm: "DELETE" }),
+ });
+ assert.equal(deletion.status, 200);
+ const remainingAcceptances = await testDb.prepare("SELECT COUNT(*) AS count FROM policy_acceptances").first();
+ assert.equal(Number(remainingAcceptances?.count ?? -1), 0);
+
+ const deletedRead = await api("/api/vault", { headers: { cookie } });
+ assert.equal(deletedRead.status, 401);
+});
diff --git a/tsconfig.json b/tsconfig.json
new file mode 100644
index 0000000..3a13f90
--- /dev/null
+++ b/tsconfig.json
@@ -0,0 +1,34 @@
+{
+ "compilerOptions": {
+ "target": "ES2017",
+ "lib": ["dom", "dom.iterable", "esnext"],
+ "allowJs": true,
+ "skipLibCheck": true,
+ "strict": true,
+ "noEmit": true,
+ "esModuleInterop": true,
+ "module": "esnext",
+ "moduleResolution": "bundler",
+ "resolveJsonModule": true,
+ "isolatedModules": true,
+ "jsx": "react-jsx",
+ "incremental": true,
+ "plugins": [
+ {
+ "name": "next"
+ }
+ ],
+ "paths": {
+ "@/*": ["./*"]
+ }
+ },
+ "include": [
+ "next-env.d.ts",
+ "**/*.ts",
+ "**/*.tsx",
+ ".next/types/**/*.ts",
+ ".next/dev/types/**/*.ts",
+ "**/*.mts"
+ ],
+ "exclude": ["node_modules"]
+}
diff --git a/vite.config.ts b/vite.config.ts
new file mode 100644
index 0000000..ae08f93
--- /dev/null
+++ b/vite.config.ts
@@ -0,0 +1,59 @@
+import vinext from "vinext";
+import { defineConfig } from "vite";
+import hostingConfig from "./.openai/hosting.json";
+import { sites } from "./build/sites-vite-plugin";
+
+const SITE_CREATOR_PLACEHOLDER_DATABASE_ID =
+ "00000000-0000-4000-8000-000000000000";
+
+const { d1, r2 } = hostingConfig;
+
+// macOS Seatbelt blocks FSEvents, so Codex previews need polling for HMR.
+const isCodexSeatbeltSandbox = process.env.CODEX_SANDBOX === "seatbelt";
+
+const localBindingConfig = {
+ main: "./worker/index.ts",
+ compatibility_flags: ["nodejs_compat"],
+ d1_databases: d1
+ ? [
+ {
+ binding: d1,
+ database_name: "site-creator-d1",
+ database_id: SITE_CREATOR_PLACEHOLDER_DATABASE_ID,
+ },
+ ]
+ : [],
+ r2_buckets: r2
+ ? [
+ {
+ binding: r2,
+ bucket_name: "site-creator-r2",
+ },
+ ]
+ : [],
+};
+
+export default defineConfig(async () => {
+ // Keep Wrangler and Miniflare state project-local. These are non-secret tool
+ // settings; application environment belongs in ignored `.env*` files.
+ process.env.WRANGLER_WRITE_LOGS ??= "false";
+ process.env.WRANGLER_LOG_PATH ??= ".wrangler/logs";
+ process.env.MINIFLARE_REGISTRY_PATH ??= ".wrangler/registry";
+
+ // Wrangler snapshots its log path while the Cloudflare plugin is imported.
+ const { cloudflare } = await import("@cloudflare/vite-plugin");
+
+ return {
+ server: isCodexSeatbeltSandbox
+ ? { watch: { useFsEvents: false, usePolling: true } }
+ : undefined,
+ plugins: [
+ vinext(),
+ sites(),
+ cloudflare({
+ viteEnvironment: { name: "rsc", childEnvironments: ["ssr"] },
+ config: localBindingConfig,
+ }),
+ ],
+ };
+});
diff --git a/worker-configuration.d.ts b/worker-configuration.d.ts
new file mode 100644
index 0000000..7deefa8
--- /dev/null
+++ b/worker-configuration.d.ts
@@ -0,0 +1,32 @@
+interface Fetcher {
+ fetch(input: RequestInfo | URL, init?: RequestInit): Promise;
+}
+
+interface D1Result {
+ results: T[];
+ success: boolean;
+ meta: Record;
+}
+
+interface D1PreparedStatement {
+ bind(...values: unknown[]): D1PreparedStatement;
+ first>(columnName?: string): Promise;
+ all>(): Promise>;
+ run>(): Promise>;
+}
+
+interface D1Database {
+ prepare(query: string): D1PreparedStatement;
+ batch(statements: D1PreparedStatement[]): Promise[]>;
+}
+
+declare module "cloudflare:workers" {
+ export const env: {
+ DB: D1Database;
+ COMMUNITY_ADMIN_EMAILS?: string;
+ OPENAI_API_KEY?: string;
+ MINIMAX_API_KEY?: string;
+ AI_PROVIDER?: string;
+ MINIMAX_REGION?: string;
+ };
+}
diff --git a/worker/index.ts b/worker/index.ts
new file mode 100644
index 0000000..b3cd137
--- /dev/null
+++ b/worker/index.ts
@@ -0,0 +1,47 @@
+/** Cloudflare Worker entry point for the vinext-starter template. */
+import { handleImageOptimization, DEFAULT_DEVICE_SIZES, DEFAULT_IMAGE_SIZES } from "vinext/server/image-optimization";
+import handler from "vinext/server/app-router-entry";
+
+interface Env {
+ ASSETS: Fetcher;
+ DB: D1Database;
+ IMAGES: {
+ input(stream: ReadableStream): {
+ transform(options: Record): {
+ output(options: { format: string; quality: number }): Promise<{ response(): Response }>;
+ };
+ };
+ };
+}
+
+interface ExecutionContext {
+ waitUntil(promise: Promise): void;
+ passThroughOnException(): void;
+}
+
+// Image security config. SVG sources with .svg extension auto-skip the
+// optimization endpoint on the client side (served directly, no proxy).
+// To route SVGs through the optimizer (with security headers), set
+// dangerouslyAllowSVG: true in next.config.js and uncomment below:
+// const imageConfig: ImageConfig = { dangerouslyAllowSVG: true };
+
+const worker = {
+ async fetch(request: Request, env: Env, ctx: ExecutionContext): Promise {
+ const url = new URL(request.url);
+
+ if (url.pathname === "/_vinext/image") {
+ const allowedWidths = [...DEFAULT_DEVICE_SIZES, ...DEFAULT_IMAGE_SIZES];
+ return handleImageOptimization(request, {
+ fetchAsset: (path) => env.ASSETS.fetch(new Request(new URL(path, request.url))),
+ transformImage: async (body, { width, format, quality }) => {
+ const result = await env.IMAGES.input(body).transform(width > 0 ? { width } : {}).output({ format, quality });
+ return result.response();
+ },
+ }, allowedWidths);
+ }
+
+ return handler.fetch(request, env, ctx);
+ },
+};
+
+export default worker;