summaryrefslogtreecommitdiffhomepage
path: root/packages/cloud/core/src
diff options
context:
space:
mode:
authorFrank <[email protected]>2025-09-18 10:59:01 -0400
committerFrank <[email protected]>2025-09-18 10:59:01 -0400
commit4ceabdffa07b1af8d99eb73622a4d549d99ec6d2 (patch)
tree72e2ae62084a9e24cc76caffbd1f30dafc69ea56 /packages/cloud/core/src
parentc87480cf931a6f8f8b55552558ef521f1918b578 (diff)
downloadopencode-4ceabdffa07b1af8d99eb73622a4d549d99ec6d2.tar.gz
opencode-4ceabdffa07b1af8d99eb73622a4d549d99ec6d2.zip
wip: zen
Diffstat (limited to 'packages/cloud/core/src')
-rw-r--r--packages/cloud/core/src/account.ts67
-rw-r--r--packages/cloud/core/src/actor.ts74
-rw-r--r--packages/cloud/core/src/billing.ts244
-rw-r--r--packages/cloud/core/src/context.ts21
-rw-r--r--packages/cloud/core/src/drizzle/index.ts86
-rw-r--r--packages/cloud/core/src/drizzle/types.ts33
-rw-r--r--packages/cloud/core/src/identifier.ts26
-rw-r--r--packages/cloud/core/src/key.ts75
-rw-r--r--packages/cloud/core/src/schema/account.sql.ts12
-rw-r--r--packages/cloud/core/src/schema/billing.sql.ts53
-rw-r--r--packages/cloud/core/src/schema/key.sql.ts22
-rw-r--r--packages/cloud/core/src/schema/user.sql.ts16
-rw-r--r--packages/cloud/core/src/schema/workspace.sql.ts21
-rw-r--r--packages/cloud/core/src/user.ts18
-rw-r--r--packages/cloud/core/src/util/env.cloudflare.ts0
-rw-r--r--packages/cloud/core/src/util/fn.ts11
-rw-r--r--packages/cloud/core/src/util/log.ts55
-rw-r--r--packages/cloud/core/src/util/memo.ts18
-rw-r--r--packages/cloud/core/src/util/price.ts3
-rw-r--r--packages/cloud/core/src/workspace.ts58
20 files changed, 0 insertions, 913 deletions
diff --git a/packages/cloud/core/src/account.ts b/packages/cloud/core/src/account.ts
deleted file mode 100644
index cb123e048..000000000
--- a/packages/cloud/core/src/account.ts
+++ /dev/null
@@ -1,67 +0,0 @@
-import { z } from "zod"
-import { and, eq, getTableColumns, isNull } from "drizzle-orm"
-import { fn } from "./util/fn"
-import { Database } from "./drizzle"
-import { Identifier } from "./identifier"
-import { AccountTable } from "./schema/account.sql"
-import { Actor } from "./actor"
-import { WorkspaceTable } from "./schema/workspace.sql"
-import { UserTable } from "./schema/user.sql"
-
-export namespace Account {
- export const create = fn(
- z.object({
- email: z.string().email(),
- id: z.string().optional(),
- }),
- async (input) =>
- Database.transaction(async (tx) => {
- const id = input.id ?? Identifier.create("account")
- await tx.insert(AccountTable).values({
- id,
- email: input.email,
- })
- return id
- }),
- )
-
- export const fromID = fn(z.string(), async (id) =>
- Database.transaction(async (tx) => {
- return tx
- .select()
- .from(AccountTable)
- .where(eq(AccountTable.id, id))
- .execute()
- .then((rows) => rows[0])
- }),
- )
-
- export const fromEmail = fn(z.string().email(), async (email) =>
- Database.transaction(async (tx) => {
- return tx
- .select()
- .from(AccountTable)
- .where(eq(AccountTable.email, email))
- .execute()
- .then((rows) => rows[0])
- }),
- )
-
- export const workspaces = async () => {
- const actor = Actor.assert("account")
- return Database.transaction(async (tx) =>
- tx
- .select(getTableColumns(WorkspaceTable))
- .from(WorkspaceTable)
- .innerJoin(UserTable, eq(UserTable.workspaceID, WorkspaceTable.id))
- .where(
- and(
- eq(UserTable.email, actor.properties.email),
- isNull(UserTable.timeDeleted),
- isNull(WorkspaceTable.timeDeleted),
- ),
- )
- .execute(),
- )
- }
-}
diff --git a/packages/cloud/core/src/actor.ts b/packages/cloud/core/src/actor.ts
deleted file mode 100644
index 0d13f7216..000000000
--- a/packages/cloud/core/src/actor.ts
+++ /dev/null
@@ -1,74 +0,0 @@
-import { Context } from "./context"
-import { Log } from "./util/log"
-
-export namespace Actor {
- interface Account {
- type: "account"
- properties: {
- accountID: string
- email: string
- }
- }
-
- interface Public {
- type: "public"
- properties: {}
- }
-
- interface User {
- type: "user"
- properties: {
- userID: string
- workspaceID: string
- }
- }
-
- interface System {
- type: "system"
- properties: {
- workspaceID: string
- }
- }
-
- export type Info = Account | Public | User | System
-
- const ctx = Context.create<Info>()
- export const use = ctx.use
-
- const log = Log.create().tag("namespace", "actor")
-
- export function provide<R, T extends Info["type"]>(
- type: T,
- properties: Extract<Info, { type: T }>["properties"],
- cb: () => R,
- ) {
- return ctx.provide(
- {
- type,
- properties,
- } as any,
- () => {
- return Log.provide({ ...properties }, () => {
- log.info("provided")
- return cb()
- })
- },
- )
- }
-
- export function assert<T extends Info["type"]>(type: T) {
- const actor = use()
- if (actor.type !== type) {
- throw new Error(`Expected actor type ${type}, got ${actor.type}`)
- }
- return actor as Extract<Info, { type: T }>
- }
-
- export function workspace() {
- const actor = use()
- if ("workspaceID" in actor.properties) {
- return actor.properties.workspaceID
- }
- throw new Error(`actor of type "${actor.type}" is not associated with a workspace`)
- }
-}
diff --git a/packages/cloud/core/src/billing.ts b/packages/cloud/core/src/billing.ts
deleted file mode 100644
index 2254adc79..000000000
--- a/packages/cloud/core/src/billing.ts
+++ /dev/null
@@ -1,244 +0,0 @@
-import { Stripe } from "stripe"
-import { Database, eq, sql } from "./drizzle"
-import { BillingTable, PaymentTable, UsageTable } from "./schema/billing.sql"
-import { Actor } from "./actor"
-import { fn } from "./util/fn"
-import { z } from "zod"
-import { User } from "./user"
-import { Resource } from "@opencode/cloud-resource"
-import { Identifier } from "./identifier"
-import { centsToMicroCents } from "./util/price"
-
-export namespace Billing {
- export const CHARGE_AMOUNT = 2000 // $20
- export const CHARGE_FEE = 123 // Stripe fee 4.4% + $0.30
- export const CHARGE_THRESHOLD = 500 // $5
- export const stripe = () =>
- new Stripe(Resource.STRIPE_SECRET_KEY.value, {
- apiVersion: "2025-03-31.basil",
- })
-
- export const get = async () => {
- return Database.use(async (tx) =>
- tx
- .select({
- customerID: BillingTable.customerID,
- paymentMethodID: BillingTable.paymentMethodID,
- paymentMethodLast4: BillingTable.paymentMethodLast4,
- balance: BillingTable.balance,
- reload: BillingTable.reload,
- monthlyLimit: BillingTable.monthlyLimit,
- monthlyUsage: BillingTable.monthlyUsage,
- timeMonthlyUsageUpdated: BillingTable.timeMonthlyUsageUpdated,
- reloadError: BillingTable.reloadError,
- timeReloadError: BillingTable.timeReloadError,
- })
- .from(BillingTable)
- .where(eq(BillingTable.workspaceID, Actor.workspace()))
- .then((r) => r[0]),
- )
- }
-
- export const payments = async () => {
- return await Database.use((tx) =>
- tx
- .select()
- .from(PaymentTable)
- .where(eq(PaymentTable.workspaceID, Actor.workspace()))
- .orderBy(sql`${PaymentTable.timeCreated} DESC`)
- .limit(100),
- )
- }
-
- export const usages = async () => {
- return await Database.use((tx) =>
- tx
- .select()
- .from(UsageTable)
- .where(eq(UsageTable.workspaceID, Actor.workspace()))
- .orderBy(sql`${UsageTable.timeCreated} DESC`)
- .limit(100),
- )
- }
-
- export const reload = async () => {
- const { customerID, paymentMethodID } = await Database.use((tx) =>
- tx
- .select({
- customerID: BillingTable.customerID,
- paymentMethodID: BillingTable.paymentMethodID,
- })
- .from(BillingTable)
- .where(eq(BillingTable.workspaceID, Actor.workspace()))
- .then((rows) => rows[0]),
- )
- const paymentID = Identifier.create("payment")
- let charge
- try {
- charge = await Billing.stripe().paymentIntents.create(
- {
- amount: Billing.CHARGE_AMOUNT + Billing.CHARGE_FEE,
- currency: "usd",
- customer: customerID!,
- payment_method: paymentMethodID!,
- off_session: true,
- confirm: true,
- },
- { idempotencyKey: paymentID },
- )
-
- if (charge.status !== "succeeded") throw new Error(charge.last_payment_error?.message)
- } catch (e: any) {
- await Database.use((tx) =>
- tx
- .update(BillingTable)
- .set({
- reloadError: e.message ?? "Payment failed.",
- timeReloadError: sql`now()`,
- })
- .where(eq(BillingTable.workspaceID, Actor.workspace())),
- )
- return
- }
-
- await Database.transaction(async (tx) => {
- await tx
- .update(BillingTable)
- .set({
- balance: sql`${BillingTable.balance} + ${centsToMicroCents(CHARGE_AMOUNT)}`,
- reloadError: null,
- timeReloadError: null,
- })
- .where(eq(BillingTable.workspaceID, Actor.workspace()))
- await tx.insert(PaymentTable).values({
- workspaceID: Actor.workspace(),
- id: paymentID,
- amount: centsToMicroCents(CHARGE_AMOUNT),
- paymentID: charge.id,
- customerID,
- })
- })
- }
-
- export const disableReload = async () => {
- return await Database.use((tx) =>
- tx
- .update(BillingTable)
- .set({
- reload: false,
- })
- .where(eq(BillingTable.workspaceID, Actor.workspace())),
- )
- }
-
- export const setMonthlyLimit = fn(z.number(), async (input) => {
- return await Database.use((tx) =>
- tx
- .update(BillingTable)
- .set({
- monthlyLimit: input,
- })
- .where(eq(BillingTable.workspaceID, Actor.workspace())),
- )
- })
-
- export const generateCheckoutUrl = fn(
- z.object({
- successUrl: z.string(),
- cancelUrl: z.string(),
- }),
- async (input) => {
- const account = Actor.assert("user")
- const { successUrl, cancelUrl } = input
-
- const user = await User.fromID(account.properties.userID)
- const customer = await Billing.get()
- const session = await Billing.stripe().checkout.sessions.create({
- mode: "payment",
- line_items: [
- {
- price_data: {
- currency: "usd",
- product_data: {
- name: "opencode credits",
- },
- unit_amount: CHARGE_AMOUNT,
- },
- quantity: 1,
- },
- {
- price_data: {
- currency: "usd",
- product_data: {
- name: "processing fee",
- },
- unit_amount: CHARGE_FEE,
- },
- quantity: 1,
- },
- ],
- payment_intent_data: {
- setup_future_usage: "on_session",
- },
- ...(customer.customerID
- ? {
- customer: customer.customerID,
- }
- : {
- customer_email: user.email,
- customer_creation: "always",
- }),
- metadata: {
- workspaceID: Actor.workspace(),
- },
- currency: "usd",
- payment_method_types: ["card"],
- payment_method_data: {
- allow_redisplay: "always",
- },
- success_url: successUrl,
- cancel_url: cancelUrl,
- })
-
- return session.url
- },
- )
-
- export const generateSessionUrl = fn(
- z.object({
- returnUrl: z.string(),
- }),
- async (input) => {
- const { returnUrl } = input
-
- const customer = await Billing.get()
- if (!customer?.customerID) {
- throw new Error("No stripe customer ID")
- }
-
- const session = await Billing.stripe().billingPortal.sessions.create({
- customer: customer.customerID,
- return_url: returnUrl,
- })
-
- return session.url
- },
- )
-
- export const generateReceiptUrl = fn(
- z.object({
- paymentID: z.string(),
- }),
- async (input) => {
- const { paymentID } = input
-
- const intent = await Billing.stripe().paymentIntents.retrieve(paymentID)
- if (!intent.latest_charge) throw new Error("No charge found")
-
- const charge = await Billing.stripe().charges.retrieve(intent.latest_charge as string)
- if (!charge.receipt_url) throw new Error("No receipt URL found")
-
- return charge.receipt_url
- },
- )
-}
diff --git a/packages/cloud/core/src/context.ts b/packages/cloud/core/src/context.ts
deleted file mode 100644
index c2ca6a313..000000000
--- a/packages/cloud/core/src/context.ts
+++ /dev/null
@@ -1,21 +0,0 @@
-import { AsyncLocalStorage } from "node:async_hooks"
-
-export namespace Context {
- export class NotFound extends Error {}
-
- export function create<T>() {
- const storage = new AsyncLocalStorage<T>()
- return {
- use() {
- const result = storage.getStore()
- if (!result) {
- throw new NotFound()
- }
- return result
- },
- provide<R>(value: T, fn: () => R) {
- return storage.run<R>(value, fn)
- },
- }
- }
-}
diff --git a/packages/cloud/core/src/drizzle/index.ts b/packages/cloud/core/src/drizzle/index.ts
deleted file mode 100644
index 806037996..000000000
--- a/packages/cloud/core/src/drizzle/index.ts
+++ /dev/null
@@ -1,86 +0,0 @@
-import { drizzle } from "drizzle-orm/planetscale-serverless"
-import { Resource } from "@opencode/cloud-resource"
-export * from "drizzle-orm"
-import { Client } from "@planetscale/database"
-
-import { MySqlTransaction, type MySqlTransactionConfig } from "drizzle-orm/mysql-core"
-import type { ExtractTablesWithRelations } from "drizzle-orm"
-import type { PlanetScalePreparedQueryHKT, PlanetscaleQueryResultHKT } from "drizzle-orm/planetscale-serverless"
-import { Context } from "../context"
-import { memo } from "../util/memo"
-
-export namespace Database {
- export type Transaction = MySqlTransaction<
- PlanetscaleQueryResultHKT,
- PlanetScalePreparedQueryHKT,
- Record<string, never>,
- ExtractTablesWithRelations<Record<string, never>>
- >
-
- const client = memo(() => {
- const result = new Client({
- host: Resource.Database.host,
- username: Resource.Database.username,
- password: Resource.Database.password,
- })
- const db = drizzle(result, {})
- return db
- })
-
- export type TxOrDb = Transaction | ReturnType<typeof client>
-
- const TransactionContext = Context.create<{
- tx: TxOrDb
- effects: (() => void | Promise<void>)[]
- }>()
-
- export async function use<T>(callback: (trx: TxOrDb) => Promise<T>) {
- try {
- const { tx } = TransactionContext.use()
- return tx.transaction(callback)
- } catch (err) {
- if (err instanceof Context.NotFound) {
- const effects: (() => void | Promise<void>)[] = []
- const result = await TransactionContext.provide(
- {
- effects,
- tx: client(),
- },
- () => callback(client()),
- )
- await Promise.all(effects.map((x) => x()))
- return result
- }
- throw err
- }
- }
- export async function fn<Input, T>(callback: (input: Input, trx: TxOrDb) => Promise<T>) {
- return (input: Input) => use(async (tx) => callback(input, tx))
- }
-
- export async function effect(effect: () => any | Promise<any>) {
- try {
- const { effects } = TransactionContext.use()
- effects.push(effect)
- } catch {
- await effect()
- }
- }
-
- export async function transaction<T>(callback: (tx: TxOrDb) => Promise<T>, config?: MySqlTransactionConfig) {
- try {
- const { tx } = TransactionContext.use()
- return callback(tx)
- } catch (err) {
- if (err instanceof Context.NotFound) {
- const effects: (() => void | Promise<void>)[] = []
- const result = await client().transaction(async (tx) => {
- return TransactionContext.provide({ tx, effects }, () => callback(tx))
- }, config)
- await Promise.all(effects.map((x) => x()))
- return result
- }
- throw err
- }
- }
-}
diff --git a/packages/cloud/core/src/drizzle/types.ts b/packages/cloud/core/src/drizzle/types.ts
deleted file mode 100644
index f16ad5a8a..000000000
--- a/packages/cloud/core/src/drizzle/types.ts
+++ /dev/null
@@ -1,33 +0,0 @@
-import { sql } from "drizzle-orm"
-import { bigint, timestamp, varchar } from "drizzle-orm/mysql-core"
-
-export const ulid = (name: string) => varchar(name, { length: 30 })
-
-export const workspaceColumns = {
- get id() {
- return ulid("id").notNull()
- },
- get workspaceID() {
- return ulid("workspace_id").notNull()
- },
-}
-
-export const id = () => ulid("id").notNull()
-
-export const utc = (name: string) =>
- timestamp(name, {
- fsp: 3,
- })
-
-export const currency = (name: string) =>
- bigint(name, {
- mode: "number",
- })
-
-export const timestamps = {
- timeCreated: utc("time_created").notNull().defaultNow(),
- timeUpdated: utc("time_updated")
- .notNull()
- .default(sql`CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)`),
- timeDeleted: utc("time_deleted"),
-}
diff --git a/packages/cloud/core/src/identifier.ts b/packages/cloud/core/src/identifier.ts
deleted file mode 100644
index f8e73852e..000000000
--- a/packages/cloud/core/src/identifier.ts
+++ /dev/null
@@ -1,26 +0,0 @@
-import { ulid } from "ulid"
-import { z } from "zod"
-
-export namespace Identifier {
- const prefixes = {
- account: "acc",
- billing: "bil",
- key: "key",
- payment: "pay",
- usage: "usg",
- user: "usr",
- workspace: "wrk",
- } as const
-
- export function create(prefix: keyof typeof prefixes, given?: string): string {
- if (given) {
- if (given.startsWith(prefixes[prefix])) return given
- throw new Error(`ID ${given} does not start with ${prefixes[prefix]}`)
- }
- return [prefixes[prefix], ulid()].join("_")
- }
-
- export function schema(prefix: keyof typeof prefixes) {
- return z.string().startsWith(prefixes[prefix])
- }
-}
diff --git a/packages/cloud/core/src/key.ts b/packages/cloud/core/src/key.ts
deleted file mode 100644
index 28643a521..000000000
--- a/packages/cloud/core/src/key.ts
+++ /dev/null
@@ -1,75 +0,0 @@
-import { z } from "zod"
-import { fn } from "./util/fn"
-import { Actor } from "./actor"
-import { and, Database, eq, isNull, sql } from "./drizzle"
-import { Identifier } from "./identifier"
-import { KeyTable } from "./schema/key.sql"
-
-export namespace Key {
- export const list = async () => {
- const workspace = Actor.workspace()
- const keys = await Database.use((tx) =>
- tx
- .select()
- .from(KeyTable)
- .where(and(eq(KeyTable.workspaceID, workspace), isNull(KeyTable.timeDeleted)))
- .orderBy(sql`${KeyTable.timeCreated} DESC`),
- )
- return keys
- }
-
- export const create = fn(z.object({ name: z.string().min(1).max(255) }), async (input) => {
- const workspaceID = Actor.workspace()
- const { name } = input
-
- // Generate secret key: sk- + 64 random characters (upper, lower, numbers)
- const chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"
- let secretKey = "sk-"
- const array = new Uint32Array(64)
- crypto.getRandomValues(array)
- for (let i = 0, l = array.length; i < l; i++) {
- secretKey += chars[array[i] % chars.length]
- }
- const keyID = Identifier.create("key")
-
- await Database.use((tx) =>
- tx.insert(KeyTable).values({
- id: keyID,
- workspaceID,
- actor: Actor.use(),
- name,
- key: secretKey,
- timeUsed: null,
- }),
- ).catch((e: any) => {
- if (e.message.match(/Duplicate entry '.*' for key 'key.name'/))
- throw new Error("A key with this name already exists. Please choose a different name.")
- throw e
- })
-
- return keyID
- })
-
- export const remove = fn(z.object({ id: z.string() }), async (input) => {
- const workspace = Actor.workspace()
- await Database.transaction(async (tx) => {
- const row = await tx
- .select({
- name: KeyTable.name,
- })
- .from(KeyTable)
- .where(and(eq(KeyTable.id, input.id), eq(KeyTable.workspaceID, workspace)))
- .then((rows) => rows[0])
- if (!row) return
-
- await tx
- .update(KeyTable)
- .set({
- timeDeleted: sql`now()`,
- oldName: row.name,
- name: input.id, // Use the key ID as the name
- })
- .where(and(eq(KeyTable.id, input.id), eq(KeyTable.workspaceID, workspace)))
- })
- })
-}
diff --git a/packages/cloud/core/src/schema/account.sql.ts b/packages/cloud/core/src/schema/account.sql.ts
deleted file mode 100644
index 4d9937114..000000000
--- a/packages/cloud/core/src/schema/account.sql.ts
+++ /dev/null
@@ -1,12 +0,0 @@
-import { mysqlTable, uniqueIndex, varchar } from "drizzle-orm/mysql-core"
-import { id, timestamps } from "../drizzle/types"
-
-export const AccountTable = mysqlTable(
- "account",
- {
- id: id(),
- ...timestamps,
- email: varchar("email", { length: 255 }).notNull(),
- },
- (table) => [uniqueIndex("email").on(table.email)],
-)
diff --git a/packages/cloud/core/src/schema/billing.sql.ts b/packages/cloud/core/src/schema/billing.sql.ts
deleted file mode 100644
index 5bec4e900..000000000
--- a/packages/cloud/core/src/schema/billing.sql.ts
+++ /dev/null
@@ -1,53 +0,0 @@
-import { bigint, boolean, int, mysqlTable, uniqueIndex, varchar } from "drizzle-orm/mysql-core"
-import { timestamps, utc, workspaceColumns } from "../drizzle/types"
-import { workspaceIndexes } from "./workspace.sql"
-
-export const BillingTable = mysqlTable(
- "billing",
- {
- ...workspaceColumns,
- ...timestamps,
- customerID: varchar("customer_id", { length: 255 }),
- paymentMethodID: varchar("payment_method_id", { length: 255 }),
- paymentMethodLast4: varchar("payment_method_last4", { length: 4 }),
- balance: bigint("balance", { mode: "number" }).notNull(),
- monthlyLimit: int("monthly_limit"),
- monthlyUsage: bigint("monthly_usage", { mode: "number" }),
- timeMonthlyUsageUpdated: utc("time_monthly_usage_updated"),
- reload: boolean("reload"),
- reloadError: varchar("reload_error", { length: 255 }),
- timeReloadError: utc("time_reload_error"),
- timeReloadLockedTill: utc("time_reload_locked_till"),
- },
- (table) => [...workspaceIndexes(table), uniqueIndex("global_customer_id").on(table.customerID)],
-)
-
-export const PaymentTable = mysqlTable(
- "payment",
- {
- ...workspaceColumns,
- ...timestamps,
- customerID: varchar("customer_id", { length: 255 }),
- paymentID: varchar("payment_id", { length: 255 }),
- amount: bigint("amount", { mode: "number" }).notNull(),
- },
- (table) => [...workspaceIndexes(table)],
-)
-
-export const UsageTable = mysqlTable(
- "usage",
- {
- ...workspaceColumns,
- ...timestamps,
- model: varchar("model", { length: 255 }).notNull(),
- provider: varchar("provider", { length: 255 }).notNull(),
- inputTokens: int("input_tokens").notNull(),
- outputTokens: int("output_tokens").notNull(),
- reasoningTokens: int("reasoning_tokens"),
- cacheReadTokens: int("cache_read_tokens"),
- cacheWrite5mTokens: int("cache_write_5m_tokens"),
- cacheWrite1hTokens: int("cache_write_1h_tokens"),
- cost: bigint("cost", { mode: "number" }).notNull(),
- },
- (table) => [...workspaceIndexes(table)],
-)
diff --git a/packages/cloud/core/src/schema/key.sql.ts b/packages/cloud/core/src/schema/key.sql.ts
deleted file mode 100644
index 98b99c788..000000000
--- a/packages/cloud/core/src/schema/key.sql.ts
+++ /dev/null
@@ -1,22 +0,0 @@
-import { mysqlTable, varchar, uniqueIndex, json } from "drizzle-orm/mysql-core"
-import { timestamps, utc, workspaceColumns } from "../drizzle/types"
-import { workspaceIndexes } from "./workspace.sql"
-import { Actor } from "../actor"
-
-export const KeyTable = mysqlTable(
- "key",
- {
- ...workspaceColumns,
- ...timestamps,
- actor: json("actor").$type<Actor.Info>(),
- name: varchar("name", { length: 255 }).notNull(),
- oldName: varchar("old_name", { length: 255 }),
- key: varchar("key", { length: 255 }).notNull(),
- timeUsed: utc("time_used"),
- },
- (table) => [
- ...workspaceIndexes(table),
- uniqueIndex("global_key").on(table.key),
- uniqueIndex("name").on(table.workspaceID, table.name),
- ],
-)
diff --git a/packages/cloud/core/src/schema/user.sql.ts b/packages/cloud/core/src/schema/user.sql.ts
deleted file mode 100644
index 00c372d1a..000000000
--- a/packages/cloud/core/src/schema/user.sql.ts
+++ /dev/null
@@ -1,16 +0,0 @@
-import { text, mysqlTable, uniqueIndex, varchar, int } from "drizzle-orm/mysql-core"
-import { timestamps, utc, workspaceColumns } from "../drizzle/types"
-import { workspaceIndexes } from "./workspace.sql"
-
-export const UserTable = mysqlTable(
- "user",
- {
- ...workspaceColumns,
- ...timestamps,
- email: varchar("email", { length: 255 }).notNull(),
- name: varchar("name", { length: 255 }).notNull(),
- timeSeen: utc("time_seen"),
- color: int("color"),
- },
- (table) => [...workspaceIndexes(table), uniqueIndex("user_email").on(table.workspaceID, table.email)],
-)
diff --git a/packages/cloud/core/src/schema/workspace.sql.ts b/packages/cloud/core/src/schema/workspace.sql.ts
deleted file mode 100644
index 979255428..000000000
--- a/packages/cloud/core/src/schema/workspace.sql.ts
+++ /dev/null
@@ -1,21 +0,0 @@
-import { primaryKey, mysqlTable, uniqueIndex, varchar } from "drizzle-orm/mysql-core"
-import { timestamps, ulid } from "../drizzle/types"
-
-export const WorkspaceTable = mysqlTable(
- "workspace",
- {
- id: ulid("id").notNull().primaryKey(),
- slug: varchar("slug", { length: 255 }),
- name: varchar("name", { length: 255 }),
- ...timestamps,
- },
- (table) => [uniqueIndex("slug").on(table.slug)],
-)
-
-export function workspaceIndexes(table: any) {
- return [
- primaryKey({
- columns: [table.workspaceID, table.id],
- }),
- ]
-}
diff --git a/packages/cloud/core/src/user.ts b/packages/cloud/core/src/user.ts
deleted file mode 100644
index 7914926ff..000000000
--- a/packages/cloud/core/src/user.ts
+++ /dev/null
@@ -1,18 +0,0 @@
-import { z } from "zod"
-import { eq } from "drizzle-orm"
-import { fn } from "./util/fn"
-import { Database } from "./drizzle"
-import { UserTable } from "./schema/user.sql"
-
-export namespace User {
- export const fromID = fn(z.string(), async (id) =>
- Database.transaction(async (tx) => {
- return tx
- .select()
- .from(UserTable)
- .where(eq(UserTable.id, id))
- .execute()
- .then((rows) => rows[0])
- }),
- )
-}
diff --git a/packages/cloud/core/src/util/env.cloudflare.ts b/packages/cloud/core/src/util/env.cloudflare.ts
deleted file mode 100644
index e69de29bb..000000000
--- a/packages/cloud/core/src/util/env.cloudflare.ts
+++ /dev/null
diff --git a/packages/cloud/core/src/util/fn.ts b/packages/cloud/core/src/util/fn.ts
deleted file mode 100644
index 9efe4622f..000000000
--- a/packages/cloud/core/src/util/fn.ts
+++ /dev/null
@@ -1,11 +0,0 @@
-import { z } from "zod"
-
-export function fn<T extends z.ZodType, Result>(schema: T, cb: (input: z.infer<T>) => Result) {
- const result = (input: z.infer<T>) => {
- const parsed = schema.parse(input)
- return cb(parsed)
- }
- result.force = (input: z.infer<T>) => cb(input)
- result.schema = schema
- return result
-}
diff --git a/packages/cloud/core/src/util/log.ts b/packages/cloud/core/src/util/log.ts
deleted file mode 100644
index 4f2d25c13..000000000
--- a/packages/cloud/core/src/util/log.ts
+++ /dev/null
@@ -1,55 +0,0 @@
-import { Context } from "../context"
-
-export namespace Log {
- const ctx = Context.create<{
- tags: Record<string, any>
- }>()
-
- export function create(tags?: Record<string, any>) {
- tags = tags || {}
-
- const result = {
- info(message?: any, extra?: Record<string, any>) {
- const prefix = Object.entries({
- ...use().tags,
- ...tags,
- ...extra,
- })
- .map(([key, value]) => `${key}=${value}`)
- .join(" ")
- console.log(prefix, message)
- return result
- },
- tag(key: string, value: string) {
- if (tags) tags[key] = value
- return result
- },
- clone() {
- return Log.create({ ...tags })
- },
- }
-
- return result
- }
-
- export function provide<R>(tags: Record<string, any>, cb: () => R) {
- const existing = use()
- return ctx.provide(
- {
- tags: {
- ...existing.tags,
- ...tags,
- },
- },
- cb,
- )
- }
-
- function use() {
- try {
- return ctx.use()
- } catch (e) {
- return { tags: {} }
- }
- }
-}
diff --git a/packages/cloud/core/src/util/memo.ts b/packages/cloud/core/src/util/memo.ts
deleted file mode 100644
index 49043010f..000000000
--- a/packages/cloud/core/src/util/memo.ts
+++ /dev/null
@@ -1,18 +0,0 @@
-export function memo<T>(fn: () => T, cleanup?: (input: T) => Promise<void>) {
- let value: T | undefined
- let loaded = false
-
- const result = (): T => {
- if (loaded) return value as T
- loaded = true
- value = fn()
- return value as T
- }
- result.reset = async () => {
- if (cleanup && value) await cleanup(value)
- loaded = false
- value = undefined
- }
-
- return result
-}
diff --git a/packages/cloud/core/src/util/price.ts b/packages/cloud/core/src/util/price.ts
deleted file mode 100644
index abdbca032..000000000
--- a/packages/cloud/core/src/util/price.ts
+++ /dev/null
@@ -1,3 +0,0 @@
-export function centsToMicroCents(amount: number) {
- return Math.round(amount * 1000000)
-}
diff --git a/packages/cloud/core/src/workspace.ts b/packages/cloud/core/src/workspace.ts
deleted file mode 100644
index a9fb923d6..000000000
--- a/packages/cloud/core/src/workspace.ts
+++ /dev/null
@@ -1,58 +0,0 @@
-import { z } from "zod"
-import { fn } from "./util/fn"
-import { centsToMicroCents } from "./util/price"
-import { Actor } from "./actor"
-import { Database, eq } from "./drizzle"
-import { Identifier } from "./identifier"
-import { UserTable } from "./schema/user.sql"
-import { BillingTable } from "./schema/billing.sql"
-import { WorkspaceTable } from "./schema/workspace.sql"
-import { Key } from "./key"
-
-export namespace Workspace {
- export const create = fn(z.void(), async () => {
- const account = Actor.assert("account")
- const workspaceID = Identifier.create("workspace")
- await Database.transaction(async (tx) => {
- await tx.insert(WorkspaceTable).values({
- id: workspaceID,
- })
- await tx.insert(UserTable).values({
- workspaceID,
- id: Identifier.create("user"),
- email: account.properties.email,
- name: "",
- })
- await tx.insert(BillingTable).values({
- workspaceID,
- id: Identifier.create("billing"),
- balance: 0,
- })
- })
- await Actor.provide(
- "system",
- {
- workspaceID,
- },
- async () => {
- await Key.create({ name: "Default API Key" })
- },
- )
- return workspaceID
- })
-
- export async function list() {
- const account = Actor.assert("account")
- return Database.use(async (tx) => {
- return tx
- .select({
- id: WorkspaceTable.id,
- slug: WorkspaceTable.slug,
- name: WorkspaceTable.name,
- })
- .from(UserTable)
- .innerJoin(WorkspaceTable, eq(UserTable.workspaceID, WorkspaceTable.id))
- .where(eq(UserTable.email, account.properties.email))
- })
- }
-}