mirror of
https://github.com/aljazceru/opencode.git
synced 2025-12-19 08:44:22 +01:00
wip: zen
This commit is contained in:
@@ -56,25 +56,36 @@ const removeMember = action(async (form: FormData) => {
|
|||||||
)
|
)
|
||||||
}, "member.remove")
|
}, "member.remove")
|
||||||
|
|
||||||
const updateMemberRole = action(async (form: FormData) => {
|
const updateMember = action(async (form: FormData) => {
|
||||||
"use server"
|
"use server"
|
||||||
|
console.log("!@#!@ Form data entries:")
|
||||||
|
for (const [key, value] of form.entries()) {
|
||||||
|
console.log(`!@#!@ ${key}:`, value)
|
||||||
|
}
|
||||||
|
|
||||||
const id = form.get("id")?.toString()
|
const id = form.get("id")?.toString()
|
||||||
if (!id) return { error: "ID is required" }
|
if (!id) return { error: "ID is required" }
|
||||||
const workspaceID = form.get("workspaceID")?.toString()
|
const workspaceID = form.get("workspaceID")?.toString()
|
||||||
if (!workspaceID) return { error: "Workspace ID is required" }
|
if (!workspaceID) return { error: "Workspace ID is required" }
|
||||||
const role = form.get("role")?.toString() as (typeof UserRole)[number]
|
const role = form.get("role")?.toString() as (typeof UserRole)[number]
|
||||||
if (!role) return { error: "Role is required" }
|
if (!role) return { error: "Role is required" }
|
||||||
|
const limit = form.get("limit")?.toString()
|
||||||
|
const monthlyLimit = limit && limit.trim() !== "" ? parseInt(limit) : null
|
||||||
|
if (monthlyLimit !== null && monthlyLimit < 0) return { error: "Set a valid monthly limit" }
|
||||||
|
|
||||||
|
console.log({ id, role, monthlyLimit, limit })
|
||||||
|
|
||||||
return json(
|
return json(
|
||||||
await withActor(
|
await withActor(
|
||||||
() =>
|
() =>
|
||||||
User.updateRole({ id, role })
|
User.update({ id, role, monthlyLimit })
|
||||||
.then((data) => ({ error: undefined, data }))
|
.then((data) => ({ error: undefined, data }))
|
||||||
.catch((e) => ({ error: e.message as string })),
|
.catch((e) => ({ error: e.message as string })),
|
||||||
workspaceID,
|
workspaceID,
|
||||||
),
|
),
|
||||||
{ revalidate: listMembers.key },
|
{ revalidate: listMembers.key },
|
||||||
)
|
)
|
||||||
}, "member.updateRole")
|
}, "member.update")
|
||||||
|
|
||||||
export function MemberCreateForm() {
|
export function MemberCreateForm() {
|
||||||
const params = useParams()
|
const params = useParams()
|
||||||
@@ -155,7 +166,7 @@ export function MemberCreateForm() {
|
|||||||
|
|
||||||
function MemberRow(props: { member: any; workspaceID: string; currentUserID: string | null }) {
|
function MemberRow(props: { member: any; workspaceID: string; currentUserID: string | null }) {
|
||||||
const [editing, setEditing] = createSignal(false)
|
const [editing, setEditing] = createSignal(false)
|
||||||
const submission = useSubmission(updateMemberRole)
|
const submission = useSubmission(updateMember)
|
||||||
const isCurrentUser = () => props.currentUserID === props.member.id
|
const isCurrentUser = () => props.currentUserID === props.member.id
|
||||||
|
|
||||||
createEffect(() => {
|
createEffect(() => {
|
||||||
@@ -164,6 +175,29 @@ function MemberRow(props: { member: any; workspaceID: string; currentUserID: str
|
|||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
|
function getUsageDisplay() {
|
||||||
|
const currentUsage = (() => {
|
||||||
|
const dateLastUsed = props.member.timeMonthlyUsageUpdated
|
||||||
|
if (!dateLastUsed) return 0
|
||||||
|
|
||||||
|
const current = new Date().toLocaleDateString("en-US", {
|
||||||
|
year: "numeric",
|
||||||
|
month: "long",
|
||||||
|
timeZone: "UTC",
|
||||||
|
})
|
||||||
|
const lastUsed = dateLastUsed.toLocaleDateString("en-US", {
|
||||||
|
year: "numeric",
|
||||||
|
month: "long",
|
||||||
|
timeZone: "UTC",
|
||||||
|
})
|
||||||
|
if (current !== lastUsed) return 0
|
||||||
|
return ((props.member.monthlyUsage ?? 0) / 100000000).toFixed(2)
|
||||||
|
})()
|
||||||
|
|
||||||
|
const limit = props.member.monthlyLimit ? `$${props.member.monthlyLimit}` : "no limit"
|
||||||
|
return `$${currentUsage} / ${limit}`
|
||||||
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Show
|
<Show
|
||||||
when={editing()}
|
when={editing()}
|
||||||
@@ -171,6 +205,7 @@ function MemberRow(props: { member: any; workspaceID: string; currentUserID: str
|
|||||||
<tr>
|
<tr>
|
||||||
<td data-slot="member-email">{props.member.accountEmail ?? props.member.email}</td>
|
<td data-slot="member-email">{props.member.accountEmail ?? props.member.email}</td>
|
||||||
<td data-slot="member-role">{props.member.role}</td>
|
<td data-slot="member-role">{props.member.role}</td>
|
||||||
|
<td data-slot="member-usage">{getUsageDisplay()}</td>
|
||||||
<Show when={!props.member.timeSeen} fallback={<td data-slot="member-joined"></td>}>
|
<Show when={!props.member.timeSeen} fallback={<td data-slot="member-joined"></td>}>
|
||||||
<td data-slot="member-joined">invited</td>
|
<td data-slot="member-joined">invited</td>
|
||||||
</Show>
|
</Show>
|
||||||
@@ -190,12 +225,21 @@ function MemberRow(props: { member: any; workspaceID: string; currentUserID: str
|
|||||||
}
|
}
|
||||||
>
|
>
|
||||||
<tr>
|
<tr>
|
||||||
<td colspan="4">
|
<td colspan="5">
|
||||||
<form action={updateMemberRole} method="post">
|
<form action={updateMember} method="post">
|
||||||
<div data-slot="edit-member-email">{props.member.accountEmail ?? props.member.email}</div>
|
<div data-slot="edit-member-email">{props.member.accountEmail ?? props.member.email}</div>
|
||||||
<input type="hidden" name="id" value={props.member.id} />
|
<input type="hidden" name="id" value={props.member.id} />
|
||||||
<input type="hidden" name="workspaceID" value={props.workspaceID} />
|
<input type="hidden" name="workspaceID" value={props.workspaceID} />
|
||||||
<Show when={!isCurrentUser()} fallback={<div data-slot="current-user-role">Role: {props.member.role}</div>}>
|
|
||||||
|
<Show
|
||||||
|
when={!isCurrentUser()}
|
||||||
|
fallback={
|
||||||
|
<>
|
||||||
|
<div data-slot="current-user-role">Role: {props.member.role}</div>
|
||||||
|
<input type="hidden" name="role" value={props.member.role} />
|
||||||
|
</>
|
||||||
|
}
|
||||||
|
>
|
||||||
<div data-slot="role-selector">
|
<div data-slot="role-selector">
|
||||||
<label>
|
<label>
|
||||||
<input type="radio" name="role" value="admin" checked={props.member.role === "admin"} />
|
<input type="radio" name="role" value="admin" checked={props.member.role === "admin"} />
|
||||||
@@ -213,18 +257,32 @@ function MemberRow(props: { member: any; workspaceID: string; currentUserID: str
|
|||||||
</label>
|
</label>
|
||||||
</div>
|
</div>
|
||||||
</Show>
|
</Show>
|
||||||
|
|
||||||
|
<div data-slot="limit-selector">
|
||||||
|
<label>
|
||||||
|
<strong>Monthly Limit</strong>
|
||||||
|
<input
|
||||||
|
type="number"
|
||||||
|
name="limit"
|
||||||
|
value={props.member.monthlyLimit ?? ""}
|
||||||
|
placeholder="No limit"
|
||||||
|
min="0"
|
||||||
|
/>
|
||||||
|
<p>Set a monthly spending limit for this user</p>
|
||||||
|
</label>
|
||||||
|
</div>
|
||||||
|
|
||||||
<Show when={submission.result && submission.result.error}>
|
<Show when={submission.result && submission.result.error}>
|
||||||
{(err) => <div data-slot="form-error">{err()}</div>}
|
{(err) => <div data-slot="form-error">{err()}</div>}
|
||||||
</Show>
|
</Show>
|
||||||
|
|
||||||
<div data-slot="form-actions">
|
<div data-slot="form-actions">
|
||||||
<button type="button" data-color="ghost" onClick={() => setEditing(false)}>
|
<button type="button" data-color="ghost" onClick={() => setEditing(false)}>
|
||||||
Cancel
|
Cancel
|
||||||
</button>
|
</button>
|
||||||
<Show when={!isCurrentUser()}>
|
<button type="submit" data-color="primary" disabled={submission.pending}>
|
||||||
<button type="submit" data-color="primary" disabled={submission.pending}>
|
{submission.pending ? "Saving..." : "Save"}
|
||||||
{submission.pending ? "Saving..." : "Save"}
|
</button>
|
||||||
</button>
|
|
||||||
</Show>
|
|
||||||
</div>
|
</div>
|
||||||
</form>
|
</form>
|
||||||
</td>
|
</td>
|
||||||
@@ -258,6 +316,7 @@ export function MemberSection() {
|
|||||||
<tr>
|
<tr>
|
||||||
<th>Email</th>
|
<th>Email</th>
|
||||||
<th>Role</th>
|
<th>Role</th>
|
||||||
|
<th>Usage</th>
|
||||||
<th></th>
|
<th></th>
|
||||||
<th></th>
|
<th></th>
|
||||||
</tr>
|
</tr>
|
||||||
|
|||||||
@@ -11,6 +11,7 @@ import { Billing } from "../../../../core/src/billing"
|
|||||||
import { Actor } from "@opencode-ai/console-core/actor.js"
|
import { Actor } from "@opencode-ai/console-core/actor.js"
|
||||||
import { WorkspaceTable } from "@opencode-ai/console-core/schema/workspace.sql.js"
|
import { WorkspaceTable } from "@opencode-ai/console-core/schema/workspace.sql.js"
|
||||||
import { ZenModel } from "@opencode-ai/console-core/model.js"
|
import { ZenModel } from "@opencode-ai/console-core/model.js"
|
||||||
|
import { UserTable } from "@opencode-ai/console-core/schema/user.sql.js"
|
||||||
|
|
||||||
export async function handler(
|
export async function handler(
|
||||||
input: APIEvent,
|
input: APIEvent,
|
||||||
@@ -33,6 +34,7 @@ export async function handler(
|
|||||||
class AuthError extends Error {}
|
class AuthError extends Error {}
|
||||||
class CreditsError extends Error {}
|
class CreditsError extends Error {}
|
||||||
class MonthlyLimitError extends Error {}
|
class MonthlyLimitError extends Error {}
|
||||||
|
class UserLimitError extends Error {}
|
||||||
class ModelError extends Error {}
|
class ModelError extends Error {}
|
||||||
|
|
||||||
type Model = z.infer<typeof ZenModel.ModelSchema>
|
type Model = z.infer<typeof ZenModel.ModelSchema>
|
||||||
@@ -181,6 +183,7 @@ export async function handler(
|
|||||||
error instanceof AuthError ||
|
error instanceof AuthError ||
|
||||||
error instanceof CreditsError ||
|
error instanceof CreditsError ||
|
||||||
error instanceof MonthlyLimitError ||
|
error instanceof MonthlyLimitError ||
|
||||||
|
error instanceof UserLimitError ||
|
||||||
error instanceof ModelError
|
error instanceof ModelError
|
||||||
)
|
)
|
||||||
return new Response(
|
return new Response(
|
||||||
@@ -243,10 +246,15 @@ export async function handler(
|
|||||||
monthlyLimit: BillingTable.monthlyLimit,
|
monthlyLimit: BillingTable.monthlyLimit,
|
||||||
monthlyUsage: BillingTable.monthlyUsage,
|
monthlyUsage: BillingTable.monthlyUsage,
|
||||||
timeMonthlyUsageUpdated: BillingTable.timeMonthlyUsageUpdated,
|
timeMonthlyUsageUpdated: BillingTable.timeMonthlyUsageUpdated,
|
||||||
|
userID: UserTable.id,
|
||||||
|
userMonthlyLimit: UserTable.monthlyLimit,
|
||||||
|
userMonthlyUsage: UserTable.monthlyUsage,
|
||||||
|
timeUserMonthlyUsageUpdated: UserTable.timeMonthlyUsageUpdated,
|
||||||
})
|
})
|
||||||
.from(KeyTable)
|
.from(KeyTable)
|
||||||
.innerJoin(WorkspaceTable, eq(WorkspaceTable.id, KeyTable.workspaceID))
|
.innerJoin(WorkspaceTable, eq(WorkspaceTable.id, KeyTable.workspaceID))
|
||||||
.innerJoin(BillingTable, eq(BillingTable.workspaceID, KeyTable.workspaceID))
|
.innerJoin(BillingTable, eq(BillingTable.workspaceID, KeyTable.workspaceID))
|
||||||
|
.innerJoin(UserTable, and(eq(UserTable.workspaceID, KeyTable.workspaceID), eq(UserTable.id, KeyTable.userID)))
|
||||||
.where(and(eq(KeyTable.key, apiKey), isNull(KeyTable.timeDeleted)))
|
.where(and(eq(KeyTable.key, apiKey), isNull(KeyTable.timeDeleted)))
|
||||||
.then((rows) => rows[0]),
|
.then((rows) => rows[0]),
|
||||||
)
|
)
|
||||||
@@ -269,6 +277,12 @@ export async function handler(
|
|||||||
monthlyUsage: data.monthlyUsage,
|
monthlyUsage: data.monthlyUsage,
|
||||||
timeMonthlyUsageUpdated: data.timeMonthlyUsageUpdated,
|
timeMonthlyUsageUpdated: data.timeMonthlyUsageUpdated,
|
||||||
},
|
},
|
||||||
|
user: {
|
||||||
|
id: data.userID,
|
||||||
|
monthlyLimit: data.userMonthlyLimit,
|
||||||
|
monthlyUsage: data.userMonthlyUsage,
|
||||||
|
timeMonthlyUsageUpdated: data.timeUserMonthlyUsageUpdated,
|
||||||
|
},
|
||||||
isFree,
|
isFree,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -280,19 +294,34 @@ export async function handler(
|
|||||||
const billing = authInfo.billing
|
const billing = authInfo.billing
|
||||||
if (!billing.paymentMethodID) throw new CreditsError("No payment method")
|
if (!billing.paymentMethodID) throw new CreditsError("No payment method")
|
||||||
if (billing.balance <= 0) throw new CreditsError("Insufficient balance")
|
if (billing.balance <= 0) throw new CreditsError("Insufficient balance")
|
||||||
|
|
||||||
|
const now = new Date()
|
||||||
|
const currentYear = now.getUTCFullYear()
|
||||||
|
const currentMonth = now.getUTCMonth()
|
||||||
if (
|
if (
|
||||||
billing.monthlyLimit &&
|
billing.monthlyLimit &&
|
||||||
billing.monthlyUsage &&
|
billing.monthlyUsage &&
|
||||||
billing.timeMonthlyUsageUpdated &&
|
billing.timeMonthlyUsageUpdated &&
|
||||||
billing.monthlyUsage >= centsToMicroCents(billing.monthlyLimit * 100)
|
billing.monthlyUsage >= centsToMicroCents(billing.monthlyLimit * 100)
|
||||||
) {
|
) {
|
||||||
const now = new Date()
|
|
||||||
const currentYear = now.getUTCFullYear()
|
|
||||||
const currentMonth = now.getUTCMonth()
|
|
||||||
const dateYear = billing.timeMonthlyUsageUpdated.getUTCFullYear()
|
const dateYear = billing.timeMonthlyUsageUpdated.getUTCFullYear()
|
||||||
const dateMonth = billing.timeMonthlyUsageUpdated.getUTCMonth()
|
const dateMonth = billing.timeMonthlyUsageUpdated.getUTCMonth()
|
||||||
if (currentYear === dateYear && currentMonth === dateMonth)
|
if (currentYear === dateYear && currentMonth === dateMonth)
|
||||||
throw new MonthlyLimitError(`You have reached your monthly spending limit of $${billing.monthlyLimit}.`)
|
throw new MonthlyLimitError(
|
||||||
|
`Your workspace has reached its monthly spending limit of $${billing.monthlyLimit}.`,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
if (
|
||||||
|
authInfo.user.monthlyLimit &&
|
||||||
|
authInfo.user.monthlyUsage &&
|
||||||
|
authInfo.user.timeMonthlyUsageUpdated &&
|
||||||
|
authInfo.user.monthlyUsage >= centsToMicroCents(authInfo.user.monthlyLimit * 100)
|
||||||
|
) {
|
||||||
|
const dateYear = authInfo.user.timeMonthlyUsageUpdated.getUTCFullYear()
|
||||||
|
const dateMonth = authInfo.user.timeMonthlyUsageUpdated.getUTCMonth()
|
||||||
|
if (currentYear === dateYear && currentMonth === dateMonth)
|
||||||
|
throw new UserLimitError(`You have reached your monthly spending limit of $${authInfo.user.monthlyLimit}.`)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -386,6 +415,18 @@ export async function handler(
|
|||||||
timeMonthlyUsageUpdated: sql`now()`,
|
timeMonthlyUsageUpdated: sql`now()`,
|
||||||
})
|
})
|
||||||
.where(eq(BillingTable.workspaceID, authInfo.workspaceID))
|
.where(eq(BillingTable.workspaceID, authInfo.workspaceID))
|
||||||
|
await tx
|
||||||
|
.update(UserTable)
|
||||||
|
.set({
|
||||||
|
monthlyUsage: sql`
|
||||||
|
CASE
|
||||||
|
WHEN MONTH(${UserTable.timeMonthlyUsageUpdated}) = MONTH(now()) AND YEAR(${UserTable.timeMonthlyUsageUpdated}) = YEAR(now()) THEN ${UserTable.monthlyUsage} + ${cost}
|
||||||
|
ELSE ${cost}
|
||||||
|
END
|
||||||
|
`,
|
||||||
|
timeMonthlyUsageUpdated: sql`now()`,
|
||||||
|
})
|
||||||
|
.where(and(eq(UserTable.workspaceID, authInfo.workspaceID), eq(UserTable.id, authInfo.user.id)))
|
||||||
})
|
})
|
||||||
|
|
||||||
await Database.use((tx) =>
|
await Database.use((tx) =>
|
||||||
|
|||||||
@@ -0,0 +1,3 @@
|
|||||||
|
ALTER TABLE `user` ADD `monthly_limit` int;--> statement-breakpoint
|
||||||
|
ALTER TABLE `user` ADD `monthly_usage` bigint;--> statement-breakpoint
|
||||||
|
ALTER TABLE `user` ADD `time_monthly_usage_updated` timestamp(3);
|
||||||
730
packages/console/core/migrations/meta/0029_snapshot.json
Normal file
730
packages/console/core/migrations/meta/0029_snapshot.json
Normal file
@@ -0,0 +1,730 @@
|
|||||||
|
{
|
||||||
|
"version": "5",
|
||||||
|
"dialect": "mysql",
|
||||||
|
"id": "33551b4c-fc2e-4753-8d9d-0971f333e65d",
|
||||||
|
"prevId": "a331e38c-c2e3-406d-a1ff-b0af7229cd85",
|
||||||
|
"tables": {
|
||||||
|
"account": {
|
||||||
|
"name": "account",
|
||||||
|
"columns": {
|
||||||
|
"id": {
|
||||||
|
"name": "id",
|
||||||
|
"type": "varchar(30)",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true,
|
||||||
|
"autoincrement": false
|
||||||
|
},
|
||||||
|
"time_created": {
|
||||||
|
"name": "time_created",
|
||||||
|
"type": "timestamp(3)",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true,
|
||||||
|
"autoincrement": false,
|
||||||
|
"default": "(now())"
|
||||||
|
},
|
||||||
|
"time_updated": {
|
||||||
|
"name": "time_updated",
|
||||||
|
"type": "timestamp(3)",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true,
|
||||||
|
"autoincrement": false,
|
||||||
|
"default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)"
|
||||||
|
},
|
||||||
|
"time_deleted": {
|
||||||
|
"name": "time_deleted",
|
||||||
|
"type": "timestamp(3)",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": false,
|
||||||
|
"autoincrement": false
|
||||||
|
},
|
||||||
|
"email": {
|
||||||
|
"name": "email",
|
||||||
|
"type": "varchar(255)",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true,
|
||||||
|
"autoincrement": false
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"indexes": {
|
||||||
|
"email": {
|
||||||
|
"name": "email",
|
||||||
|
"columns": [
|
||||||
|
"email"
|
||||||
|
],
|
||||||
|
"isUnique": true
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"foreignKeys": {},
|
||||||
|
"compositePrimaryKeys": {},
|
||||||
|
"uniqueConstraints": {},
|
||||||
|
"checkConstraint": {}
|
||||||
|
},
|
||||||
|
"billing": {
|
||||||
|
"name": "billing",
|
||||||
|
"columns": {
|
||||||
|
"id": {
|
||||||
|
"name": "id",
|
||||||
|
"type": "varchar(30)",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true,
|
||||||
|
"autoincrement": false
|
||||||
|
},
|
||||||
|
"workspace_id": {
|
||||||
|
"name": "workspace_id",
|
||||||
|
"type": "varchar(30)",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true,
|
||||||
|
"autoincrement": false
|
||||||
|
},
|
||||||
|
"time_created": {
|
||||||
|
"name": "time_created",
|
||||||
|
"type": "timestamp(3)",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true,
|
||||||
|
"autoincrement": false,
|
||||||
|
"default": "(now())"
|
||||||
|
},
|
||||||
|
"time_updated": {
|
||||||
|
"name": "time_updated",
|
||||||
|
"type": "timestamp(3)",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true,
|
||||||
|
"autoincrement": false,
|
||||||
|
"default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)"
|
||||||
|
},
|
||||||
|
"time_deleted": {
|
||||||
|
"name": "time_deleted",
|
||||||
|
"type": "timestamp(3)",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": false,
|
||||||
|
"autoincrement": false
|
||||||
|
},
|
||||||
|
"customer_id": {
|
||||||
|
"name": "customer_id",
|
||||||
|
"type": "varchar(255)",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": false,
|
||||||
|
"autoincrement": false
|
||||||
|
},
|
||||||
|
"payment_method_id": {
|
||||||
|
"name": "payment_method_id",
|
||||||
|
"type": "varchar(255)",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": false,
|
||||||
|
"autoincrement": false
|
||||||
|
},
|
||||||
|
"payment_method_last4": {
|
||||||
|
"name": "payment_method_last4",
|
||||||
|
"type": "varchar(4)",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": false,
|
||||||
|
"autoincrement": false
|
||||||
|
},
|
||||||
|
"balance": {
|
||||||
|
"name": "balance",
|
||||||
|
"type": "bigint",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true,
|
||||||
|
"autoincrement": false
|
||||||
|
},
|
||||||
|
"monthly_limit": {
|
||||||
|
"name": "monthly_limit",
|
||||||
|
"type": "int",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": false,
|
||||||
|
"autoincrement": false
|
||||||
|
},
|
||||||
|
"monthly_usage": {
|
||||||
|
"name": "monthly_usage",
|
||||||
|
"type": "bigint",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": false,
|
||||||
|
"autoincrement": false
|
||||||
|
},
|
||||||
|
"time_monthly_usage_updated": {
|
||||||
|
"name": "time_monthly_usage_updated",
|
||||||
|
"type": "timestamp(3)",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": false,
|
||||||
|
"autoincrement": false
|
||||||
|
},
|
||||||
|
"reload": {
|
||||||
|
"name": "reload",
|
||||||
|
"type": "boolean",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": false,
|
||||||
|
"autoincrement": false
|
||||||
|
},
|
||||||
|
"reload_error": {
|
||||||
|
"name": "reload_error",
|
||||||
|
"type": "varchar(255)",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": false,
|
||||||
|
"autoincrement": false
|
||||||
|
},
|
||||||
|
"time_reload_error": {
|
||||||
|
"name": "time_reload_error",
|
||||||
|
"type": "timestamp(3)",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": false,
|
||||||
|
"autoincrement": false
|
||||||
|
},
|
||||||
|
"time_reload_locked_till": {
|
||||||
|
"name": "time_reload_locked_till",
|
||||||
|
"type": "timestamp(3)",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": false,
|
||||||
|
"autoincrement": false
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"indexes": {
|
||||||
|
"global_customer_id": {
|
||||||
|
"name": "global_customer_id",
|
||||||
|
"columns": [
|
||||||
|
"customer_id"
|
||||||
|
],
|
||||||
|
"isUnique": true
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"foreignKeys": {},
|
||||||
|
"compositePrimaryKeys": {
|
||||||
|
"billing_workspace_id_id_pk": {
|
||||||
|
"name": "billing_workspace_id_id_pk",
|
||||||
|
"columns": [
|
||||||
|
"workspace_id",
|
||||||
|
"id"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"uniqueConstraints": {},
|
||||||
|
"checkConstraint": {}
|
||||||
|
},
|
||||||
|
"payment": {
|
||||||
|
"name": "payment",
|
||||||
|
"columns": {
|
||||||
|
"id": {
|
||||||
|
"name": "id",
|
||||||
|
"type": "varchar(30)",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true,
|
||||||
|
"autoincrement": false
|
||||||
|
},
|
||||||
|
"workspace_id": {
|
||||||
|
"name": "workspace_id",
|
||||||
|
"type": "varchar(30)",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true,
|
||||||
|
"autoincrement": false
|
||||||
|
},
|
||||||
|
"time_created": {
|
||||||
|
"name": "time_created",
|
||||||
|
"type": "timestamp(3)",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true,
|
||||||
|
"autoincrement": false,
|
||||||
|
"default": "(now())"
|
||||||
|
},
|
||||||
|
"time_updated": {
|
||||||
|
"name": "time_updated",
|
||||||
|
"type": "timestamp(3)",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true,
|
||||||
|
"autoincrement": false,
|
||||||
|
"default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)"
|
||||||
|
},
|
||||||
|
"time_deleted": {
|
||||||
|
"name": "time_deleted",
|
||||||
|
"type": "timestamp(3)",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": false,
|
||||||
|
"autoincrement": false
|
||||||
|
},
|
||||||
|
"customer_id": {
|
||||||
|
"name": "customer_id",
|
||||||
|
"type": "varchar(255)",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": false,
|
||||||
|
"autoincrement": false
|
||||||
|
},
|
||||||
|
"invoice_id": {
|
||||||
|
"name": "invoice_id",
|
||||||
|
"type": "varchar(255)",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": false,
|
||||||
|
"autoincrement": false
|
||||||
|
},
|
||||||
|
"payment_id": {
|
||||||
|
"name": "payment_id",
|
||||||
|
"type": "varchar(255)",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": false,
|
||||||
|
"autoincrement": false
|
||||||
|
},
|
||||||
|
"amount": {
|
||||||
|
"name": "amount",
|
||||||
|
"type": "bigint",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true,
|
||||||
|
"autoincrement": false
|
||||||
|
},
|
||||||
|
"time_refunded": {
|
||||||
|
"name": "time_refunded",
|
||||||
|
"type": "timestamp(3)",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": false,
|
||||||
|
"autoincrement": false
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"indexes": {},
|
||||||
|
"foreignKeys": {},
|
||||||
|
"compositePrimaryKeys": {
|
||||||
|
"payment_workspace_id_id_pk": {
|
||||||
|
"name": "payment_workspace_id_id_pk",
|
||||||
|
"columns": [
|
||||||
|
"workspace_id",
|
||||||
|
"id"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"uniqueConstraints": {},
|
||||||
|
"checkConstraint": {}
|
||||||
|
},
|
||||||
|
"usage": {
|
||||||
|
"name": "usage",
|
||||||
|
"columns": {
|
||||||
|
"id": {
|
||||||
|
"name": "id",
|
||||||
|
"type": "varchar(30)",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true,
|
||||||
|
"autoincrement": false
|
||||||
|
},
|
||||||
|
"workspace_id": {
|
||||||
|
"name": "workspace_id",
|
||||||
|
"type": "varchar(30)",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true,
|
||||||
|
"autoincrement": false
|
||||||
|
},
|
||||||
|
"time_created": {
|
||||||
|
"name": "time_created",
|
||||||
|
"type": "timestamp(3)",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true,
|
||||||
|
"autoincrement": false,
|
||||||
|
"default": "(now())"
|
||||||
|
},
|
||||||
|
"time_updated": {
|
||||||
|
"name": "time_updated",
|
||||||
|
"type": "timestamp(3)",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true,
|
||||||
|
"autoincrement": false,
|
||||||
|
"default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)"
|
||||||
|
},
|
||||||
|
"time_deleted": {
|
||||||
|
"name": "time_deleted",
|
||||||
|
"type": "timestamp(3)",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": false,
|
||||||
|
"autoincrement": false
|
||||||
|
},
|
||||||
|
"model": {
|
||||||
|
"name": "model",
|
||||||
|
"type": "varchar(255)",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true,
|
||||||
|
"autoincrement": false
|
||||||
|
},
|
||||||
|
"provider": {
|
||||||
|
"name": "provider",
|
||||||
|
"type": "varchar(255)",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true,
|
||||||
|
"autoincrement": false
|
||||||
|
},
|
||||||
|
"input_tokens": {
|
||||||
|
"name": "input_tokens",
|
||||||
|
"type": "int",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true,
|
||||||
|
"autoincrement": false
|
||||||
|
},
|
||||||
|
"output_tokens": {
|
||||||
|
"name": "output_tokens",
|
||||||
|
"type": "int",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true,
|
||||||
|
"autoincrement": false
|
||||||
|
},
|
||||||
|
"reasoning_tokens": {
|
||||||
|
"name": "reasoning_tokens",
|
||||||
|
"type": "int",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": false,
|
||||||
|
"autoincrement": false
|
||||||
|
},
|
||||||
|
"cache_read_tokens": {
|
||||||
|
"name": "cache_read_tokens",
|
||||||
|
"type": "int",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": false,
|
||||||
|
"autoincrement": false
|
||||||
|
},
|
||||||
|
"cache_write_5m_tokens": {
|
||||||
|
"name": "cache_write_5m_tokens",
|
||||||
|
"type": "int",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": false,
|
||||||
|
"autoincrement": false
|
||||||
|
},
|
||||||
|
"cache_write_1h_tokens": {
|
||||||
|
"name": "cache_write_1h_tokens",
|
||||||
|
"type": "int",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": false,
|
||||||
|
"autoincrement": false
|
||||||
|
},
|
||||||
|
"cost": {
|
||||||
|
"name": "cost",
|
||||||
|
"type": "bigint",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true,
|
||||||
|
"autoincrement": false
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"indexes": {},
|
||||||
|
"foreignKeys": {},
|
||||||
|
"compositePrimaryKeys": {
|
||||||
|
"usage_workspace_id_id_pk": {
|
||||||
|
"name": "usage_workspace_id_id_pk",
|
||||||
|
"columns": [
|
||||||
|
"workspace_id",
|
||||||
|
"id"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"uniqueConstraints": {},
|
||||||
|
"checkConstraint": {}
|
||||||
|
},
|
||||||
|
"key": {
|
||||||
|
"name": "key",
|
||||||
|
"columns": {
|
||||||
|
"id": {
|
||||||
|
"name": "id",
|
||||||
|
"type": "varchar(30)",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true,
|
||||||
|
"autoincrement": false
|
||||||
|
},
|
||||||
|
"workspace_id": {
|
||||||
|
"name": "workspace_id",
|
||||||
|
"type": "varchar(30)",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true,
|
||||||
|
"autoincrement": false
|
||||||
|
},
|
||||||
|
"time_created": {
|
||||||
|
"name": "time_created",
|
||||||
|
"type": "timestamp(3)",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true,
|
||||||
|
"autoincrement": false,
|
||||||
|
"default": "(now())"
|
||||||
|
},
|
||||||
|
"time_updated": {
|
||||||
|
"name": "time_updated",
|
||||||
|
"type": "timestamp(3)",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true,
|
||||||
|
"autoincrement": false,
|
||||||
|
"default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)"
|
||||||
|
},
|
||||||
|
"time_deleted": {
|
||||||
|
"name": "time_deleted",
|
||||||
|
"type": "timestamp(3)",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": false,
|
||||||
|
"autoincrement": false
|
||||||
|
},
|
||||||
|
"name": {
|
||||||
|
"name": "name",
|
||||||
|
"type": "varchar(255)",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true,
|
||||||
|
"autoincrement": false
|
||||||
|
},
|
||||||
|
"key": {
|
||||||
|
"name": "key",
|
||||||
|
"type": "varchar(255)",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true,
|
||||||
|
"autoincrement": false
|
||||||
|
},
|
||||||
|
"user_id": {
|
||||||
|
"name": "user_id",
|
||||||
|
"type": "varchar(30)",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true,
|
||||||
|
"autoincrement": false
|
||||||
|
},
|
||||||
|
"time_used": {
|
||||||
|
"name": "time_used",
|
||||||
|
"type": "timestamp(3)",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": false,
|
||||||
|
"autoincrement": false
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"indexes": {
|
||||||
|
"global_key": {
|
||||||
|
"name": "global_key",
|
||||||
|
"columns": [
|
||||||
|
"key"
|
||||||
|
],
|
||||||
|
"isUnique": true
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"foreignKeys": {},
|
||||||
|
"compositePrimaryKeys": {
|
||||||
|
"key_workspace_id_id_pk": {
|
||||||
|
"name": "key_workspace_id_id_pk",
|
||||||
|
"columns": [
|
||||||
|
"workspace_id",
|
||||||
|
"id"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"uniqueConstraints": {},
|
||||||
|
"checkConstraint": {}
|
||||||
|
},
|
||||||
|
"user": {
|
||||||
|
"name": "user",
|
||||||
|
"columns": {
|
||||||
|
"id": {
|
||||||
|
"name": "id",
|
||||||
|
"type": "varchar(30)",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true,
|
||||||
|
"autoincrement": false
|
||||||
|
},
|
||||||
|
"workspace_id": {
|
||||||
|
"name": "workspace_id",
|
||||||
|
"type": "varchar(30)",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true,
|
||||||
|
"autoincrement": false
|
||||||
|
},
|
||||||
|
"time_created": {
|
||||||
|
"name": "time_created",
|
||||||
|
"type": "timestamp(3)",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true,
|
||||||
|
"autoincrement": false,
|
||||||
|
"default": "(now())"
|
||||||
|
},
|
||||||
|
"time_updated": {
|
||||||
|
"name": "time_updated",
|
||||||
|
"type": "timestamp(3)",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true,
|
||||||
|
"autoincrement": false,
|
||||||
|
"default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)"
|
||||||
|
},
|
||||||
|
"time_deleted": {
|
||||||
|
"name": "time_deleted",
|
||||||
|
"type": "timestamp(3)",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": false,
|
||||||
|
"autoincrement": false
|
||||||
|
},
|
||||||
|
"account_id": {
|
||||||
|
"name": "account_id",
|
||||||
|
"type": "varchar(30)",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": false,
|
||||||
|
"autoincrement": false
|
||||||
|
},
|
||||||
|
"email": {
|
||||||
|
"name": "email",
|
||||||
|
"type": "varchar(255)",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": false,
|
||||||
|
"autoincrement": false
|
||||||
|
},
|
||||||
|
"name": {
|
||||||
|
"name": "name",
|
||||||
|
"type": "varchar(255)",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true,
|
||||||
|
"autoincrement": false
|
||||||
|
},
|
||||||
|
"time_seen": {
|
||||||
|
"name": "time_seen",
|
||||||
|
"type": "timestamp(3)",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": false,
|
||||||
|
"autoincrement": false
|
||||||
|
},
|
||||||
|
"color": {
|
||||||
|
"name": "color",
|
||||||
|
"type": "int",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": false,
|
||||||
|
"autoincrement": false
|
||||||
|
},
|
||||||
|
"role": {
|
||||||
|
"name": "role",
|
||||||
|
"type": "enum('admin','member')",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true,
|
||||||
|
"autoincrement": false
|
||||||
|
},
|
||||||
|
"monthly_limit": {
|
||||||
|
"name": "monthly_limit",
|
||||||
|
"type": "int",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": false,
|
||||||
|
"autoincrement": false
|
||||||
|
},
|
||||||
|
"monthly_usage": {
|
||||||
|
"name": "monthly_usage",
|
||||||
|
"type": "bigint",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": false,
|
||||||
|
"autoincrement": false
|
||||||
|
},
|
||||||
|
"time_monthly_usage_updated": {
|
||||||
|
"name": "time_monthly_usage_updated",
|
||||||
|
"type": "timestamp(3)",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": false,
|
||||||
|
"autoincrement": false
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"indexes": {
|
||||||
|
"user_account_id": {
|
||||||
|
"name": "user_account_id",
|
||||||
|
"columns": [
|
||||||
|
"workspace_id",
|
||||||
|
"account_id"
|
||||||
|
],
|
||||||
|
"isUnique": true
|
||||||
|
},
|
||||||
|
"user_email": {
|
||||||
|
"name": "user_email",
|
||||||
|
"columns": [
|
||||||
|
"workspace_id",
|
||||||
|
"email"
|
||||||
|
],
|
||||||
|
"isUnique": true
|
||||||
|
},
|
||||||
|
"global_account_id": {
|
||||||
|
"name": "global_account_id",
|
||||||
|
"columns": [
|
||||||
|
"account_id"
|
||||||
|
],
|
||||||
|
"isUnique": false
|
||||||
|
},
|
||||||
|
"global_email": {
|
||||||
|
"name": "global_email",
|
||||||
|
"columns": [
|
||||||
|
"email"
|
||||||
|
],
|
||||||
|
"isUnique": false
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"foreignKeys": {},
|
||||||
|
"compositePrimaryKeys": {
|
||||||
|
"user_workspace_id_id_pk": {
|
||||||
|
"name": "user_workspace_id_id_pk",
|
||||||
|
"columns": [
|
||||||
|
"workspace_id",
|
||||||
|
"id"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"uniqueConstraints": {},
|
||||||
|
"checkConstraint": {}
|
||||||
|
},
|
||||||
|
"workspace": {
|
||||||
|
"name": "workspace",
|
||||||
|
"columns": {
|
||||||
|
"id": {
|
||||||
|
"name": "id",
|
||||||
|
"type": "varchar(30)",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true,
|
||||||
|
"autoincrement": false
|
||||||
|
},
|
||||||
|
"slug": {
|
||||||
|
"name": "slug",
|
||||||
|
"type": "varchar(255)",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": false,
|
||||||
|
"autoincrement": false
|
||||||
|
},
|
||||||
|
"name": {
|
||||||
|
"name": "name",
|
||||||
|
"type": "varchar(255)",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true,
|
||||||
|
"autoincrement": false
|
||||||
|
},
|
||||||
|
"time_created": {
|
||||||
|
"name": "time_created",
|
||||||
|
"type": "timestamp(3)",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true,
|
||||||
|
"autoincrement": false,
|
||||||
|
"default": "(now())"
|
||||||
|
},
|
||||||
|
"time_updated": {
|
||||||
|
"name": "time_updated",
|
||||||
|
"type": "timestamp(3)",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true,
|
||||||
|
"autoincrement": false,
|
||||||
|
"default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)"
|
||||||
|
},
|
||||||
|
"time_deleted": {
|
||||||
|
"name": "time_deleted",
|
||||||
|
"type": "timestamp(3)",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": false,
|
||||||
|
"autoincrement": false
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"indexes": {
|
||||||
|
"slug": {
|
||||||
|
"name": "slug",
|
||||||
|
"columns": [
|
||||||
|
"slug"
|
||||||
|
],
|
||||||
|
"isUnique": true
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"foreignKeys": {},
|
||||||
|
"compositePrimaryKeys": {
|
||||||
|
"workspace_id": {
|
||||||
|
"name": "workspace_id",
|
||||||
|
"columns": [
|
||||||
|
"id"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"uniqueConstraints": {},
|
||||||
|
"checkConstraint": {}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"views": {},
|
||||||
|
"_meta": {
|
||||||
|
"schemas": {},
|
||||||
|
"tables": {},
|
||||||
|
"columns": {}
|
||||||
|
},
|
||||||
|
"internal": {
|
||||||
|
"tables": {},
|
||||||
|
"indexes": {}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -204,6 +204,13 @@
|
|||||||
"when": 1759805025276,
|
"when": 1759805025276,
|
||||||
"tag": "0028_careful_cerise",
|
"tag": "0028_careful_cerise",
|
||||||
"breakpoints": true
|
"breakpoints": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"idx": 29,
|
||||||
|
"version": "5",
|
||||||
|
"when": 1759811835558,
|
||||||
|
"tag": "0029_panoramic_harrier",
|
||||||
|
"breakpoints": true
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
@@ -1,5 +1,5 @@
|
|||||||
import { Stripe } from "stripe"
|
import { Stripe } from "stripe"
|
||||||
import { and, Database, eq, sql } from "./drizzle"
|
import { Database, eq, sql } from "./drizzle"
|
||||||
import { BillingTable, PaymentTable, UsageTable } from "./schema/billing.sql"
|
import { BillingTable, PaymentTable, UsageTable } from "./schema/billing.sql"
|
||||||
import { Actor } from "./actor"
|
import { Actor } from "./actor"
|
||||||
import { fn } from "./util/fn"
|
import { fn } from "./util/fn"
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
import { mysqlTable, uniqueIndex, varchar, int, mysqlEnum, index } from "drizzle-orm/mysql-core"
|
import { mysqlTable, uniqueIndex, varchar, int, mysqlEnum, index, bigint } from "drizzle-orm/mysql-core"
|
||||||
import { timestamps, ulid, utc, workspaceColumns } from "../drizzle/types"
|
import { timestamps, ulid, utc, workspaceColumns } from "../drizzle/types"
|
||||||
import { workspaceIndexes } from "./workspace.sql"
|
import { workspaceIndexes } from "./workspace.sql"
|
||||||
|
|
||||||
@@ -15,6 +15,9 @@ export const UserTable = mysqlTable(
|
|||||||
timeSeen: utc("time_seen"),
|
timeSeen: utc("time_seen"),
|
||||||
color: int("color"),
|
color: int("color"),
|
||||||
role: mysqlEnum("role", UserRole).notNull(),
|
role: mysqlEnum("role", UserRole).notNull(),
|
||||||
|
monthlyLimit: int("monthly_limit"),
|
||||||
|
monthlyUsage: bigint("monthly_usage", { mode: "number" }),
|
||||||
|
timeMonthlyUsageUpdated: utc("time_monthly_usage_updated"),
|
||||||
},
|
},
|
||||||
(table) => [
|
(table) => [
|
||||||
...workspaceIndexes(table),
|
...workspaceIndexes(table),
|
||||||
|
|||||||
@@ -174,18 +174,19 @@ export namespace User {
|
|||||||
)
|
)
|
||||||
})
|
})
|
||||||
|
|
||||||
export const updateRole = fn(
|
export const update = fn(
|
||||||
z.object({
|
z.object({
|
||||||
id: z.string(),
|
id: z.string(),
|
||||||
role: z.enum(UserRole),
|
role: z.enum(UserRole),
|
||||||
|
monthlyLimit: z.number().nullable(),
|
||||||
}),
|
}),
|
||||||
async ({ id, role }) => {
|
async ({ id, role, monthlyLimit }) => {
|
||||||
await assertAdmin()
|
await assertAdmin()
|
||||||
if (role === "member") assertNotSelf(id)
|
if (role === "member") assertNotSelf(id)
|
||||||
return await Database.use((tx) =>
|
return await Database.use((tx) =>
|
||||||
tx
|
tx
|
||||||
.update(UserTable)
|
.update(UserTable)
|
||||||
.set({ role })
|
.set({ role, monthlyLimit })
|
||||||
.where(and(eq(UserTable.id, id), eq(UserTable.workspaceID, Actor.workspace()))),
|
.where(and(eq(UserTable.id, id), eq(UserTable.workspaceID, Actor.workspace()))),
|
||||||
)
|
)
|
||||||
},
|
},
|
||||||
|
|||||||
Reference in New Issue
Block a user