
-
Reliable optimized models for coding agents
+
Reliable optimized models for coding agents
Zen gives you access to a curated set of AI models that OpenCode has tested and benchmarked specifically
for coding agents. No need to worry about inconsistent performance and quality, use validated models
diff --git a/packages/console/app/src/routes/zen/util/error.ts b/packages/console/app/src/routes/zen/util/error.ts
index dfc7e9fc..f1e13146 100644
--- a/packages/console/app/src/routes/zen/util/error.ts
+++ b/packages/console/app/src/routes/zen/util/error.ts
@@ -3,3 +3,4 @@ export class CreditsError extends Error {}
export class MonthlyLimitError extends Error {}
export class UserLimitError extends Error {}
export class ModelError extends Error {}
+export class RateLimitError extends Error {}
diff --git a/packages/console/app/src/routes/zen/util/handler.ts b/packages/console/app/src/routes/zen/util/handler.ts
index 0d46e858..edaac3a7 100644
--- a/packages/console/app/src/routes/zen/util/handler.ts
+++ b/packages/console/app/src/routes/zen/util/handler.ts
@@ -12,18 +12,14 @@ import { UserTable } from "@opencode-ai/console-core/schema/user.sql.js"
import { ModelTable } from "@opencode-ai/console-core/schema/model.sql.js"
import { ProviderTable } from "@opencode-ai/console-core/schema/provider.sql.js"
import { logger } from "./logger"
-import { AuthError, CreditsError, MonthlyLimitError, UserLimitError, ModelError } from "./error"
-import {
- createBodyConverter,
- createStreamPartConverter,
- createResponseConverter,
-} from "./provider/provider"
+import { AuthError, CreditsError, MonthlyLimitError, UserLimitError, ModelError, RateLimitError } from "./error"
+import { createBodyConverter, createStreamPartConverter, createResponseConverter } from "./provider/provider"
import { anthropicHelper } from "./provider/anthropic"
import { openaiHelper } from "./provider/openai"
import { oaCompatHelper } from "./provider/openai-compatible"
+import { createRateLimiter } from "./rateLimiter"
type ZenData = Awaited>
-type Model = ZenData["models"][string]
export async function handler(
input: APIEvent,
@@ -32,6 +28,10 @@ export async function handler(
parseApiKey: (headers: Headers) => string | undefined
},
) {
+ type AuthInfo = Awaited>
+ type ModelInfo = Awaited>
+ type ProviderInfo = Awaited>
+
const FREE_WORKSPACES = [
"wrk_01K46JDFR0E75SG2Q8K172KF3Y", // frank
"wrk_01K6W1A3VE0KMNVSCQT43BG2SX", // opencode bench
@@ -39,6 +39,7 @@ export async function handler(
try {
const body = await input.request.json()
+ const ip = input.request.headers.get("x-real-ip") ?? ""
logger.metric({
is_tream: !!body.stream,
session: input.request.headers.get("x-opencode-session"),
@@ -46,13 +47,11 @@ export async function handler(
})
const zenData = ZenData.list()
const modelInfo = validateModel(zenData, body.model)
- const providerInfo = selectProvider(
- zenData,
- modelInfo,
- input.request.headers.get("x-real-ip") ?? "",
- )
+ const providerInfo = selectProvider(zenData, modelInfo, ip)
const authInfo = await authenticate(modelInfo, providerInfo)
- validateBilling(modelInfo, authInfo)
+ const rateLimiter = createRateLimiter(modelInfo.id, modelInfo.rateLimit, ip)
+ await rateLimiter?.check()
+ validateBilling(authInfo, modelInfo)
validateModelSettings(authInfo)
updateProviderKey(authInfo, providerInfo)
logger.metric({ provider: providerInfo.id })
@@ -67,7 +66,7 @@ export async function handler(
}),
)
logger.debug("REQUEST URL: " + reqUrl)
- logger.debug("REQUEST: " + reqBody)
+ logger.debug("REQUEST: " + reqBody.substring(0, 300) + "...")
const res = await fetch(reqUrl, {
method: "POST",
headers: (() => {
@@ -92,9 +91,6 @@ export async function handler(
}
}
logger.debug("STATUS: " + res.status + " " + res.statusText)
- if (res.status === 400 || res.status === 503) {
- logger.debug("RESPONSE: " + (await res.text()))
- }
// Handle non-streaming response
if (!body.stream) {
@@ -103,6 +99,7 @@ export async function handler(
const body = JSON.stringify(responseConverter(json))
logger.metric({ response_length: body.length })
logger.debug("RESPONSE: " + body)
+ await rateLimiter?.track()
await trackUsage(authInfo, modelInfo, providerInfo, json.usage)
await reload(authInfo)
return new Response(body, {
@@ -131,6 +128,7 @@ export async function handler(
response_length: responseLength,
"timestamp.last_byte": Date.now(),
})
+ await rateLimiter?.track()
const usage = usageParser.retrieve()
if (usage) {
await trackUsage(authInfo, modelInfo, providerInfo, usage)
@@ -205,6 +203,15 @@ export async function handler(
{ status: 401 },
)
+ if (error instanceof RateLimitError)
+ return new Response(
+ JSON.stringify({
+ type: "error",
+ error: { type: error.constructor.name, message: error.message },
+ }),
+ { status: 429 },
+ )
+
return new Response(
JSON.stringify({
type: "error",
@@ -229,12 +236,8 @@ export async function handler(
return { id: modelId, ...modelData }
}
- function selectProvider(
- zenData: ZenData,
- model: Awaited>,
- ip: string,
- ) {
- const providers = model.providers
+ function selectProvider(zenData: ZenData, modelInfo: ModelInfo, ip: string) {
+ const providers = modelInfo.providers
.filter((provider) => !provider.disabled)
.flatMap((provider) => Array(provider.weight ?? 1).fill(provider))
@@ -247,26 +250,22 @@ export async function handler(
throw new ModelError(`Provider ${provider.id} not supported`)
}
- const format = zenData.providers[provider.id].format
-
return {
...provider,
...zenData.providers[provider.id],
- ...(format === "anthropic"
- ? anthropicHelper
- : format === "openai"
- ? openaiHelper
- : oaCompatHelper),
+ ...(() => {
+ const format = zenData.providers[provider.id].format
+ if (format === "anthropic") return anthropicHelper
+ if (format === "openai") return openaiHelper
+ return oaCompatHelper
+ })(),
}
}
- async function authenticate(
- model: Awaited>,
- providerInfo: Awaited>,
- ) {
+ async function authenticate(modelInfo: ModelInfo, providerInfo: ProviderInfo) {
const apiKey = opts.parseApiKey(input.request.headers)
if (!apiKey) {
- if (model.allowAnonymous) return
+ if (modelInfo.allowAnonymous) return
throw new AuthError("Missing API key.")
}
@@ -281,6 +280,7 @@ export async function handler(
monthlyLimit: BillingTable.monthlyLimit,
monthlyUsage: BillingTable.monthlyUsage,
timeMonthlyUsageUpdated: BillingTable.timeMonthlyUsageUpdated,
+ reloadTrigger: BillingTable.reloadTrigger,
},
user: {
id: UserTable.id,
@@ -296,20 +296,11 @@ export async function handler(
.from(KeyTable)
.innerJoin(WorkspaceTable, eq(WorkspaceTable.id, KeyTable.workspaceID))
.innerJoin(BillingTable, eq(BillingTable.workspaceID, KeyTable.workspaceID))
- .innerJoin(
- UserTable,
- and(eq(UserTable.workspaceID, KeyTable.workspaceID), eq(UserTable.id, KeyTable.userID)),
- )
- .leftJoin(
- ModelTable,
- and(eq(ModelTable.workspaceID, KeyTable.workspaceID), eq(ModelTable.model, model.id)),
- )
+ .innerJoin(UserTable, and(eq(UserTable.workspaceID, KeyTable.workspaceID), eq(UserTable.id, KeyTable.userID)))
+ .leftJoin(ModelTable, and(eq(ModelTable.workspaceID, KeyTable.workspaceID), eq(ModelTable.model, modelInfo.id)))
.leftJoin(
ProviderTable,
- and(
- eq(ProviderTable.workspaceID, KeyTable.workspaceID),
- eq(ProviderTable.provider, providerInfo.id),
- ),
+ and(eq(ProviderTable.workspaceID, KeyTable.workspaceID), eq(ProviderTable.provider, providerInfo.id)),
)
.where(and(eq(KeyTable.key, apiKey), isNull(KeyTable.timeDeleted)))
.then((rows) => rows[0]),
@@ -332,11 +323,11 @@ export async function handler(
}
}
- function validateBilling(model: Model, authInfo: Awaited>) {
+ function validateBilling(authInfo: AuthInfo, modelInfo: ModelInfo) {
if (!authInfo) return
if (authInfo.provider?.credentials) return
if (authInfo.isFree) return
- if (model.allowAnonymous) return
+ if (modelInfo.allowAnonymous) return
const billing = authInfo.billing
if (!billing.paymentMethodID)
@@ -380,39 +371,24 @@ export async function handler(
}
}
- function validateModelSettings(authInfo: Awaited>) {
+ function validateModelSettings(authInfo: AuthInfo) {
if (!authInfo) return
if (authInfo.isDisabled) throw new ModelError("Model is disabled")
}
- function updateProviderKey(
- authInfo: Awaited>,
- providerInfo: Awaited>,
- ) {
+ function updateProviderKey(authInfo: AuthInfo, providerInfo: ProviderInfo) {
if (!authInfo) return
if (!authInfo.provider?.credentials) return
providerInfo.apiKey = authInfo.provider.credentials
}
- async function trackUsage(
- authInfo: Awaited>,
- modelInfo: ReturnType,
- providerInfo: Awaited>,
- usage: any,
- ) {
- const {
- inputTokens,
- outputTokens,
- reasoningTokens,
- cacheReadTokens,
- cacheWrite5mTokens,
- cacheWrite1hTokens,
- } = providerInfo.normalizeUsage(usage)
+ async function trackUsage(authInfo: AuthInfo, modelInfo: ModelInfo, providerInfo: ProviderInfo, usage: any) {
+ const { inputTokens, outputTokens, reasoningTokens, cacheReadTokens, cacheWrite5mTokens, cacheWrite1hTokens } =
+ providerInfo.normalizeUsage(usage)
const modelCost =
modelInfo.cost200K &&
- inputTokens + (cacheReadTokens ?? 0) + (cacheWrite5mTokens ?? 0) + (cacheWrite1hTokens ?? 0) >
- 200_000
+ inputTokens + (cacheReadTokens ?? 0) + (cacheWrite5mTokens ?? 0) + (cacheWrite1hTokens ?? 0) > 200_000
? modelInfo.cost200K
: modelInfo.cost
@@ -463,8 +439,7 @@ export async function handler(
if (!authInfo) return
- const cost =
- authInfo.isFree || authInfo.provider?.credentials ? 0 : centsToMicroCents(totalCostInCent)
+ const cost = authInfo.isFree || authInfo.provider?.credentials ? 0 : centsToMicroCents(totalCostInCent)
await Database.transaction(async (tx) => {
await tx.insert(UsageTable).values({
workspaceID: authInfo.workspaceID,
@@ -504,9 +479,7 @@ export async function handler(
`,
timeMonthlyUsageUpdated: sql`now()`,
})
- .where(
- and(eq(UserTable.workspaceID, authInfo.workspaceID), eq(UserTable.id, authInfo.user.id)),
- )
+ .where(and(eq(UserTable.workspaceID, authInfo.workspaceID), eq(UserTable.id, authInfo.user.id)))
})
await Database.use((tx) =>
@@ -517,7 +490,7 @@ export async function handler(
)
}
- async function reload(authInfo: Awaited>) {
+ async function reload(authInfo: AuthInfo) {
if (!authInfo) return
if (authInfo.isFree) return
if (authInfo.provider?.credentials) return
@@ -532,11 +505,11 @@ export async function handler(
and(
eq(BillingTable.workspaceID, authInfo.workspaceID),
eq(BillingTable.reload, true),
- lt(BillingTable.balance, centsToMicroCents(Billing.CHARGE_THRESHOLD)),
- or(
- isNull(BillingTable.timeReloadLockedTill),
- lt(BillingTable.timeReloadLockedTill, sql`now()`),
+ lt(
+ BillingTable.balance,
+ centsToMicroCents((authInfo.billing.reloadTrigger ?? Billing.RELOAD_TRIGGER) * 100),
),
+ or(isNull(BillingTable.timeReloadLockedTill), lt(BillingTable.timeReloadLockedTill, sql`now()`)),
),
),
)
diff --git a/packages/console/app/src/routes/zen/util/provider/anthropic.ts b/packages/console/app/src/routes/zen/util/provider/anthropic.ts
index 603d8917..d8d1cd74 100644
--- a/packages/console/app/src/routes/zen/util/provider/anthropic.ts
+++ b/packages/console/app/src/routes/zen/util/provider/anthropic.ts
@@ -98,7 +98,10 @@ export function fromAnthropicRequest(body: any): CommonRequest {
typeof (src as any).media_type === "string" &&
typeof (src as any).data === "string"
)
- return { type: "image_url", image_url: { url: `data:${(src as any).media_type};base64,${(src as any).data}` } }
+ return {
+ type: "image_url",
+ image_url: { url: `data:${(src as any).media_type};base64,${(src as any).data}` },
+ }
return undefined
}
@@ -165,7 +168,11 @@ export function fromAnthropicRequest(body: any): CommonRequest {
.filter((t: any) => t && typeof t === "object" && "input_schema" in t)
.map((t: any) => ({
type: "function",
- function: { name: (t as any).name, description: (t as any).description, parameters: (t as any).input_schema },
+ function: {
+ name: (t as any).name,
+ description: (t as any).description,
+ parameters: (t as any).input_schema,
+ },
}))
: undefined
@@ -452,7 +459,12 @@ export function toAnthropicResponse(resp: CommonResponse) {
} catch {
input = (tc as any).function.arguments
}
- content.push({ type: "tool_use", id: (tc as any).id, name: (tc as any).function.name, input })
+ content.push({
+ type: "tool_use",
+ id: (tc as any).id,
+ name: (tc as any).function.name,
+ input,
+ })
}
}
}
@@ -511,13 +523,22 @@ export function fromAnthropicChunk(chunk: string): CommonChunk | string {
if (json.type === "content_block_start") {
const cb = json.content_block
if (cb?.type === "text") {
- out.choices.push({ index: json.index ?? 0, delta: { role: "assistant", content: "" }, finish_reason: null })
+ out.choices.push({
+ index: json.index ?? 0,
+ delta: { role: "assistant", content: "" },
+ finish_reason: null,
+ })
} else if (cb?.type === "tool_use") {
out.choices.push({
index: json.index ?? 0,
delta: {
tool_calls: [
- { index: json.index ?? 0, id: cb.id, type: "function", function: { name: cb.name, arguments: "" } },
+ {
+ index: json.index ?? 0,
+ id: cb.id,
+ type: "function",
+ function: { name: cb.name, arguments: "" },
+ },
],
},
finish_reason: null,
@@ -532,7 +553,9 @@ export function fromAnthropicChunk(chunk: string): CommonChunk | string {
} else if (d?.type === "input_json_delta") {
out.choices.push({
index: json.index ?? 0,
- delta: { tool_calls: [{ index: json.index ?? 0, function: { arguments: d.partial_json } }] },
+ delta: {
+ tool_calls: [{ index: json.index ?? 0, function: { arguments: d.partial_json } }],
+ },
finish_reason: null,
})
}
diff --git a/packages/console/app/src/routes/zen/util/provider/openai-compatible.ts b/packages/console/app/src/routes/zen/util/provider/openai-compatible.ts
index daf65027..8a9170ef 100644
--- a/packages/console/app/src/routes/zen/util/provider/openai-compatible.ts
+++ b/packages/console/app/src/routes/zen/util/provider/openai-compatible.ts
@@ -532,7 +532,9 @@ export function toOaCompatibleChunk(chunk: CommonChunk): string {
total_tokens: chunk.usage.total_tokens,
...(chunk.usage.prompt_tokens_details?.cached_tokens
? {
- prompt_tokens_details: { cached_tokens: chunk.usage.prompt_tokens_details.cached_tokens },
+ prompt_tokens_details: {
+ cached_tokens: chunk.usage.prompt_tokens_details.cached_tokens,
+ },
}
: {}),
}
diff --git a/packages/console/app/src/routes/zen/util/provider/openai.ts b/packages/console/app/src/routes/zen/util/provider/openai.ts
index d1730099..e79e8357 100644
--- a/packages/console/app/src/routes/zen/util/provider/openai.ts
+++ b/packages/console/app/src/routes/zen/util/provider/openai.ts
@@ -77,7 +77,10 @@ export function fromOpenaiRequest(body: any): CommonRequest {
typeof (s as any).media_type === "string" &&
typeof (s as any).data === "string"
)
- return { type: "image_url", image_url: { url: `data:${(s as any).media_type};base64,${(s as any).data}` } }
+ return {
+ type: "image_url",
+ image_url: { url: `data:${(s as any).media_type};base64,${(s as any).data}` },
+ }
return undefined
}
@@ -153,7 +156,11 @@ export function fromOpenaiRequest(body: any): CommonRequest {
}
if ((m as any).role === "tool") {
- msgs.push({ role: "tool", tool_call_id: (m as any).tool_call_id, content: (m as any).content })
+ msgs.push({
+ role: "tool",
+ tool_call_id: (m as any).tool_call_id,
+ content: (m as any).content,
+ })
continue
}
}
@@ -210,7 +217,10 @@ export function toOpenaiRequest(body: CommonRequest) {
typeof (s as any).media_type === "string" &&
typeof (s as any).data === "string"
)
- return { type: "input_image", image_url: { url: `data:${(s as any).media_type};base64,${(s as any).data}` } }
+ return {
+ type: "input_image",
+ image_url: { url: `data:${(s as any).media_type};base64,${(s as any).data}` },
+ }
return undefined
}
@@ -498,7 +508,9 @@ export function fromOpenaiChunk(chunk: string): CommonChunk | string {
if (typeof name === "string" && name.length > 0) {
out.choices.push({
index: 0,
- delta: { tool_calls: [{ index: 0, id, type: "function", function: { name, arguments: "" } }] },
+ delta: {
+ tool_calls: [{ index: 0, id, type: "function", function: { name, arguments: "" } }],
+ },
finish_reason: null,
})
}
@@ -555,7 +567,12 @@ export function toOpenaiChunk(chunk: CommonChunk): string {
const model = chunk.model
if (d.content) {
- const data = { id, type: "response.output_text.delta", delta: d.content, response: { id, model } }
+ const data = {
+ id,
+ type: "response.output_text.delta",
+ delta: d.content,
+ response: { id, model },
+ }
return `event: response.output_text.delta\ndata: ${JSON.stringify(data)}`
}
@@ -565,7 +582,13 @@ export function toOpenaiChunk(chunk: CommonChunk): string {
const data = {
type: "response.output_item.added",
output_index: 0,
- item: { id: tc.id, type: "function_call", name: tc.function.name, call_id: tc.id, arguments: "" },
+ item: {
+ id: tc.id,
+ type: "function_call",
+ name: tc.function.name,
+ call_id: tc.id,
+ arguments: "",
+ },
}
return `event: response.output_item.added\ndata: ${JSON.stringify(data)}`
}
@@ -593,7 +616,11 @@ export function toOpenaiChunk(chunk: CommonChunk): string {
}
: undefined
- const data: any = { id, type: "response.completed", response: { id, model, ...(usage ? { usage } : {}) } }
+ const data: any = {
+ id,
+ type: "response.completed",
+ response: { id, model, ...(usage ? { usage } : {}) },
+ }
return `event: response.completed\ndata: ${JSON.stringify(data)}`
}
diff --git a/packages/console/app/src/routes/zen/util/rateLimiter.ts b/packages/console/app/src/routes/zen/util/rateLimiter.ts
new file mode 100644
index 00000000..b3c03681
--- /dev/null
+++ b/packages/console/app/src/routes/zen/util/rateLimiter.ts
@@ -0,0 +1,35 @@
+import { Resource } from "@opencode-ai/console-resource"
+import { RateLimitError } from "./error"
+import { logger } from "./logger"
+
+export function createRateLimiter(model: string, limit: number | undefined, ip: string) {
+ if (!limit) return
+
+ const now = Date.now()
+ const currKey = `usage:${ip}:${model}:${buildYYYYMMDDHH(now)}`
+ const prevKey = `usage:${ip}:${model}:${buildYYYYMMDDHH(now - 3_600_000)}`
+ let currRate: number
+ let prevRate: number
+
+ return {
+ track: async () => {
+ await Resource.GatewayKv.put(currKey, currRate + 1, { expirationTtl: 3600 })
+ },
+ check: async () => {
+ const values = await Resource.GatewayKv.get([currKey, prevKey])
+ const prevValue = values?.get(prevKey)
+ const currValue = values?.get(currKey)
+ prevRate = prevValue ? parseInt(prevValue) : 0
+ currRate = currValue ? parseInt(currValue) : 0
+ logger.debug(`rate limit ${model} prev/curr: ${prevRate}/${currRate}`)
+ if (prevRate + currRate >= limit) throw new RateLimitError(`Rate limit exceeded. Please try again later.`)
+ },
+ }
+}
+
+function buildYYYYMMDDHH(timestamp: number) {
+ return new Date(timestamp)
+ .toISOString()
+ .replace(/[^0-9]/g, "")
+ .substring(0, 10)
+}
diff --git a/packages/console/app/src/routes/zen/v1/models.ts b/packages/console/app/src/routes/zen/v1/models.ts
index 3d0c3147..ee2b3ab5 100644
--- a/packages/console/app/src/routes/zen/v1/models.ts
+++ b/packages/console/app/src/routes/zen/v1/models.ts
@@ -50,10 +50,7 @@ export async function GET(input: APIEvent) {
})
.from(KeyTable)
.innerJoin(WorkspaceTable, eq(WorkspaceTable.id, KeyTable.workspaceID))
- .leftJoin(
- ModelTable,
- and(eq(ModelTable.workspaceID, KeyTable.workspaceID), isNull(ModelTable.timeDeleted)),
- )
+ .leftJoin(ModelTable, and(eq(ModelTable.workspaceID, KeyTable.workspaceID), isNull(ModelTable.timeDeleted)))
.where(and(eq(KeyTable.key, apiKey), isNull(KeyTable.timeDeleted)))
.then((rows) => rows.map((row) => row.model)),
)
diff --git a/packages/console/app/sst-env.d.ts b/packages/console/app/sst-env.d.ts
index 9b9de732..bd558821 100644
--- a/packages/console/app/sst-env.d.ts
+++ b/packages/console/app/sst-env.d.ts
@@ -6,4 +6,4 @@
///
import "sst"
-export {}
\ No newline at end of file
+export {}
diff --git a/packages/console/core/migrations/meta/0018_snapshot.json b/packages/console/core/migrations/meta/0018_snapshot.json
index 398ba261..3e3c64c7 100644
--- a/packages/console/core/migrations/meta/0018_snapshot.json
+++ b/packages/console/core/migrations/meta/0018_snapshot.json
@@ -48,9 +48,7 @@
"indexes": {
"email": {
"name": "email",
- "columns": [
- "email"
- ],
+ "columns": ["email"],
"isUnique": true
}
},
@@ -180,9 +178,7 @@
"indexes": {
"global_customer_id": {
"name": "global_customer_id",
- "columns": [
- "customer_id"
- ],
+ "columns": ["customer_id"],
"isUnique": true
}
},
@@ -190,10 +186,7 @@
"compositePrimaryKeys": {
"billing_workspace_id_id_pk": {
"name": "billing_workspace_id_id_pk",
- "columns": [
- "workspace_id",
- "id"
- ]
+ "columns": ["workspace_id", "id"]
}
},
"uniqueConstraints": {},
@@ -280,10 +273,7 @@
"compositePrimaryKeys": {
"payment_workspace_id_id_pk": {
"name": "payment_workspace_id_id_pk",
- "columns": [
- "workspace_id",
- "id"
- ]
+ "columns": ["workspace_id", "id"]
}
},
"uniqueConstraints": {},
@@ -398,10 +388,7 @@
"compositePrimaryKeys": {
"usage_workspace_id_id_pk": {
"name": "usage_workspace_id_id_pk",
- "columns": [
- "workspace_id",
- "id"
- ]
+ "columns": ["workspace_id", "id"]
}
},
"uniqueConstraints": {},
@@ -486,17 +473,12 @@
"indexes": {
"global_key": {
"name": "global_key",
- "columns": [
- "key"
- ],
+ "columns": ["key"],
"isUnique": true
},
"name": {
"name": "name",
- "columns": [
- "workspace_id",
- "name"
- ],
+ "columns": ["workspace_id", "name"],
"isUnique": true
}
},
@@ -504,10 +486,7 @@
"compositePrimaryKeys": {
"key_workspace_id_id_pk": {
"name": "key_workspace_id_id_pk",
- "columns": [
- "workspace_id",
- "id"
- ]
+ "columns": ["workspace_id", "id"]
}
},
"uniqueConstraints": {},
@@ -599,10 +578,7 @@
"indexes": {
"user_email": {
"name": "user_email",
- "columns": [
- "workspace_id",
- "email"
- ],
+ "columns": ["workspace_id", "email"],
"isUnique": true
}
},
@@ -610,10 +586,7 @@
"compositePrimaryKeys": {
"user_workspace_id_id_pk": {
"name": "user_workspace_id_id_pk",
- "columns": [
- "workspace_id",
- "id"
- ]
+ "columns": ["workspace_id", "id"]
}
},
"uniqueConstraints": {},
@@ -670,9 +643,7 @@
"indexes": {
"slug": {
"name": "slug",
- "columns": [
- "slug"
- ],
+ "columns": ["slug"],
"isUnique": true
}
},
@@ -680,9 +651,7 @@
"compositePrimaryKeys": {
"workspace_id": {
"name": "workspace_id",
- "columns": [
- "id"
- ]
+ "columns": ["id"]
}
},
"uniqueConstraints": {},
@@ -699,4 +668,4 @@
"tables": {},
"indexes": {}
}
-}
\ No newline at end of file
+}
diff --git a/packages/console/core/migrations/meta/0019_snapshot.json b/packages/console/core/migrations/meta/0019_snapshot.json
index 8f1afeb5..9a0d4d24 100644
--- a/packages/console/core/migrations/meta/0019_snapshot.json
+++ b/packages/console/core/migrations/meta/0019_snapshot.json
@@ -48,9 +48,7 @@
"indexes": {
"email": {
"name": "email",
- "columns": [
- "email"
- ],
+ "columns": ["email"],
"isUnique": true
}
},
@@ -180,9 +178,7 @@
"indexes": {
"global_customer_id": {
"name": "global_customer_id",
- "columns": [
- "customer_id"
- ],
+ "columns": ["customer_id"],
"isUnique": true
}
},
@@ -190,10 +186,7 @@
"compositePrimaryKeys": {
"billing_workspace_id_id_pk": {
"name": "billing_workspace_id_id_pk",
- "columns": [
- "workspace_id",
- "id"
- ]
+ "columns": ["workspace_id", "id"]
}
},
"uniqueConstraints": {},
@@ -280,10 +273,7 @@
"compositePrimaryKeys": {
"payment_workspace_id_id_pk": {
"name": "payment_workspace_id_id_pk",
- "columns": [
- "workspace_id",
- "id"
- ]
+ "columns": ["workspace_id", "id"]
}
},
"uniqueConstraints": {},
@@ -398,10 +388,7 @@
"compositePrimaryKeys": {
"usage_workspace_id_id_pk": {
"name": "usage_workspace_id_id_pk",
- "columns": [
- "workspace_id",
- "id"
- ]
+ "columns": ["workspace_id", "id"]
}
},
"uniqueConstraints": {},
@@ -486,17 +473,12 @@
"indexes": {
"global_key": {
"name": "global_key",
- "columns": [
- "key"
- ],
+ "columns": ["key"],
"isUnique": true
},
"name": {
"name": "name",
- "columns": [
- "workspace_id",
- "name"
- ],
+ "columns": ["workspace_id", "name"],
"isUnique": true
}
},
@@ -504,10 +486,7 @@
"compositePrimaryKeys": {
"key_workspace_id_id_pk": {
"name": "key_workspace_id_id_pk",
- "columns": [
- "workspace_id",
- "id"
- ]
+ "columns": ["workspace_id", "id"]
}
},
"uniqueConstraints": {},
@@ -599,10 +578,7 @@
"indexes": {
"user_email": {
"name": "user_email",
- "columns": [
- "workspace_id",
- "email"
- ],
+ "columns": ["workspace_id", "email"],
"isUnique": true
}
},
@@ -610,10 +586,7 @@
"compositePrimaryKeys": {
"user_workspace_id_id_pk": {
"name": "user_workspace_id_id_pk",
- "columns": [
- "workspace_id",
- "id"
- ]
+ "columns": ["workspace_id", "id"]
}
},
"uniqueConstraints": {},
@@ -670,9 +643,7 @@
"indexes": {
"slug": {
"name": "slug",
- "columns": [
- "slug"
- ],
+ "columns": ["slug"],
"isUnique": true
}
},
@@ -680,9 +651,7 @@
"compositePrimaryKeys": {
"workspace_id": {
"name": "workspace_id",
- "columns": [
- "id"
- ]
+ "columns": ["id"]
}
},
"uniqueConstraints": {},
@@ -699,4 +668,4 @@
"tables": {},
"indexes": {}
}
-}
\ No newline at end of file
+}
diff --git a/packages/console/core/migrations/meta/0020_snapshot.json b/packages/console/core/migrations/meta/0020_snapshot.json
index 662093f5..9defceb5 100644
--- a/packages/console/core/migrations/meta/0020_snapshot.json
+++ b/packages/console/core/migrations/meta/0020_snapshot.json
@@ -48,9 +48,7 @@
"indexes": {
"email": {
"name": "email",
- "columns": [
- "email"
- ],
+ "columns": ["email"],
"isUnique": true
}
},
@@ -180,9 +178,7 @@
"indexes": {
"global_customer_id": {
"name": "global_customer_id",
- "columns": [
- "customer_id"
- ],
+ "columns": ["customer_id"],
"isUnique": true
}
},
@@ -190,10 +186,7 @@
"compositePrimaryKeys": {
"billing_workspace_id_id_pk": {
"name": "billing_workspace_id_id_pk",
- "columns": [
- "workspace_id",
- "id"
- ]
+ "columns": ["workspace_id", "id"]
}
},
"uniqueConstraints": {},
@@ -280,10 +273,7 @@
"compositePrimaryKeys": {
"payment_workspace_id_id_pk": {
"name": "payment_workspace_id_id_pk",
- "columns": [
- "workspace_id",
- "id"
- ]
+ "columns": ["workspace_id", "id"]
}
},
"uniqueConstraints": {},
@@ -398,10 +388,7 @@
"compositePrimaryKeys": {
"usage_workspace_id_id_pk": {
"name": "usage_workspace_id_id_pk",
- "columns": [
- "workspace_id",
- "id"
- ]
+ "columns": ["workspace_id", "id"]
}
},
"uniqueConstraints": {},
@@ -486,17 +473,12 @@
"indexes": {
"global_key": {
"name": "global_key",
- "columns": [
- "key"
- ],
+ "columns": ["key"],
"isUnique": true
},
"name": {
"name": "name",
- "columns": [
- "workspace_id",
- "name"
- ],
+ "columns": ["workspace_id", "name"],
"isUnique": true
}
},
@@ -504,10 +486,7 @@
"compositePrimaryKeys": {
"key_workspace_id_id_pk": {
"name": "key_workspace_id_id_pk",
- "columns": [
- "workspace_id",
- "id"
- ]
+ "columns": ["workspace_id", "id"]
}
},
"uniqueConstraints": {},
@@ -592,10 +571,7 @@
"indexes": {
"user_email": {
"name": "user_email",
- "columns": [
- "workspace_id",
- "email"
- ],
+ "columns": ["workspace_id", "email"],
"isUnique": true
}
},
@@ -603,10 +579,7 @@
"compositePrimaryKeys": {
"user_workspace_id_id_pk": {
"name": "user_workspace_id_id_pk",
- "columns": [
- "workspace_id",
- "id"
- ]
+ "columns": ["workspace_id", "id"]
}
},
"uniqueConstraints": {},
@@ -663,9 +636,7 @@
"indexes": {
"slug": {
"name": "slug",
- "columns": [
- "slug"
- ],
+ "columns": ["slug"],
"isUnique": true
}
},
@@ -673,9 +644,7 @@
"compositePrimaryKeys": {
"workspace_id": {
"name": "workspace_id",
- "columns": [
- "id"
- ]
+ "columns": ["id"]
}
},
"uniqueConstraints": {},
@@ -692,4 +661,4 @@
"tables": {},
"indexes": {}
}
-}
\ No newline at end of file
+}
diff --git a/packages/console/core/migrations/meta/0021_snapshot.json b/packages/console/core/migrations/meta/0021_snapshot.json
index b285e34f..64d3e9d2 100644
--- a/packages/console/core/migrations/meta/0021_snapshot.json
+++ b/packages/console/core/migrations/meta/0021_snapshot.json
@@ -48,9 +48,7 @@
"indexes": {
"email": {
"name": "email",
- "columns": [
- "email"
- ],
+ "columns": ["email"],
"isUnique": true
}
},
@@ -180,9 +178,7 @@
"indexes": {
"global_customer_id": {
"name": "global_customer_id",
- "columns": [
- "customer_id"
- ],
+ "columns": ["customer_id"],
"isUnique": true
}
},
@@ -190,10 +186,7 @@
"compositePrimaryKeys": {
"billing_workspace_id_id_pk": {
"name": "billing_workspace_id_id_pk",
- "columns": [
- "workspace_id",
- "id"
- ]
+ "columns": ["workspace_id", "id"]
}
},
"uniqueConstraints": {},
@@ -280,10 +273,7 @@
"compositePrimaryKeys": {
"payment_workspace_id_id_pk": {
"name": "payment_workspace_id_id_pk",
- "columns": [
- "workspace_id",
- "id"
- ]
+ "columns": ["workspace_id", "id"]
}
},
"uniqueConstraints": {},
@@ -398,10 +388,7 @@
"compositePrimaryKeys": {
"usage_workspace_id_id_pk": {
"name": "usage_workspace_id_id_pk",
- "columns": [
- "workspace_id",
- "id"
- ]
+ "columns": ["workspace_id", "id"]
}
},
"uniqueConstraints": {},
@@ -486,17 +473,12 @@
"indexes": {
"global_key": {
"name": "global_key",
- "columns": [
- "key"
- ],
+ "columns": ["key"],
"isUnique": true
},
"name": {
"name": "name",
- "columns": [
- "workspace_id",
- "name"
- ],
+ "columns": ["workspace_id", "name"],
"isUnique": true
}
},
@@ -504,10 +486,7 @@
"compositePrimaryKeys": {
"key_workspace_id_id_pk": {
"name": "key_workspace_id_id_pk",
- "columns": [
- "workspace_id",
- "id"
- ]
+ "columns": ["workspace_id", "id"]
}
},
"uniqueConstraints": {},
@@ -599,10 +578,7 @@
"indexes": {
"user_email": {
"name": "user_email",
- "columns": [
- "workspace_id",
- "email"
- ],
+ "columns": ["workspace_id", "email"],
"isUnique": true
}
},
@@ -610,10 +586,7 @@
"compositePrimaryKeys": {
"user_workspace_id_id_pk": {
"name": "user_workspace_id_id_pk",
- "columns": [
- "workspace_id",
- "id"
- ]
+ "columns": ["workspace_id", "id"]
}
},
"uniqueConstraints": {},
@@ -670,9 +643,7 @@
"indexes": {
"slug": {
"name": "slug",
- "columns": [
- "slug"
- ],
+ "columns": ["slug"],
"isUnique": true
}
},
@@ -680,9 +651,7 @@
"compositePrimaryKeys": {
"workspace_id": {
"name": "workspace_id",
- "columns": [
- "id"
- ]
+ "columns": ["id"]
}
},
"uniqueConstraints": {},
@@ -699,4 +668,4 @@
"tables": {},
"indexes": {}
}
-}
\ No newline at end of file
+}
diff --git a/packages/console/core/migrations/meta/0022_snapshot.json b/packages/console/core/migrations/meta/0022_snapshot.json
index 9486ee34..8a1c4e7d 100644
--- a/packages/console/core/migrations/meta/0022_snapshot.json
+++ b/packages/console/core/migrations/meta/0022_snapshot.json
@@ -48,9 +48,7 @@
"indexes": {
"email": {
"name": "email",
- "columns": [
- "email"
- ],
+ "columns": ["email"],
"isUnique": true
}
},
@@ -180,9 +178,7 @@
"indexes": {
"global_customer_id": {
"name": "global_customer_id",
- "columns": [
- "customer_id"
- ],
+ "columns": ["customer_id"],
"isUnique": true
}
},
@@ -190,10 +186,7 @@
"compositePrimaryKeys": {
"billing_workspace_id_id_pk": {
"name": "billing_workspace_id_id_pk",
- "columns": [
- "workspace_id",
- "id"
- ]
+ "columns": ["workspace_id", "id"]
}
},
"uniqueConstraints": {},
@@ -280,10 +273,7 @@
"compositePrimaryKeys": {
"payment_workspace_id_id_pk": {
"name": "payment_workspace_id_id_pk",
- "columns": [
- "workspace_id",
- "id"
- ]
+ "columns": ["workspace_id", "id"]
}
},
"uniqueConstraints": {},
@@ -398,10 +388,7 @@
"compositePrimaryKeys": {
"usage_workspace_id_id_pk": {
"name": "usage_workspace_id_id_pk",
- "columns": [
- "workspace_id",
- "id"
- ]
+ "columns": ["workspace_id", "id"]
}
},
"uniqueConstraints": {},
@@ -486,17 +473,12 @@
"indexes": {
"global_key": {
"name": "global_key",
- "columns": [
- "key"
- ],
+ "columns": ["key"],
"isUnique": true
},
"name": {
"name": "name",
- "columns": [
- "workspace_id",
- "name"
- ],
+ "columns": ["workspace_id", "name"],
"isUnique": true
}
},
@@ -504,10 +486,7 @@
"compositePrimaryKeys": {
"key_workspace_id_id_pk": {
"name": "key_workspace_id_id_pk",
- "columns": [
- "workspace_id",
- "id"
- ]
+ "columns": ["workspace_id", "id"]
}
},
"uniqueConstraints": {},
@@ -613,18 +592,12 @@
"indexes": {
"user_account_id": {
"name": "user_account_id",
- "columns": [
- "workspace_id",
- "account_id"
- ],
+ "columns": ["workspace_id", "account_id"],
"isUnique": true
},
"user_email": {
"name": "user_email",
- "columns": [
- "workspace_id",
- "email"
- ],
+ "columns": ["workspace_id", "email"],
"isUnique": true
}
},
@@ -632,10 +605,7 @@
"compositePrimaryKeys": {
"user_workspace_id_id_pk": {
"name": "user_workspace_id_id_pk",
- "columns": [
- "workspace_id",
- "id"
- ]
+ "columns": ["workspace_id", "id"]
}
},
"uniqueConstraints": {},
@@ -692,9 +662,7 @@
"indexes": {
"slug": {
"name": "slug",
- "columns": [
- "slug"
- ],
+ "columns": ["slug"],
"isUnique": true
}
},
@@ -702,9 +670,7 @@
"compositePrimaryKeys": {
"workspace_id": {
"name": "workspace_id",
- "columns": [
- "id"
- ]
+ "columns": ["id"]
}
},
"uniqueConstraints": {},
@@ -721,4 +687,4 @@
"tables": {},
"indexes": {}
}
-}
\ No newline at end of file
+}
diff --git a/packages/console/core/migrations/meta/0023_snapshot.json b/packages/console/core/migrations/meta/0023_snapshot.json
index 8a40e42a..4f6f6628 100644
--- a/packages/console/core/migrations/meta/0023_snapshot.json
+++ b/packages/console/core/migrations/meta/0023_snapshot.json
@@ -48,9 +48,7 @@
"indexes": {
"email": {
"name": "email",
- "columns": [
- "email"
- ],
+ "columns": ["email"],
"isUnique": true
}
},
@@ -180,9 +178,7 @@
"indexes": {
"global_customer_id": {
"name": "global_customer_id",
- "columns": [
- "customer_id"
- ],
+ "columns": ["customer_id"],
"isUnique": true
}
},
@@ -190,10 +186,7 @@
"compositePrimaryKeys": {
"billing_workspace_id_id_pk": {
"name": "billing_workspace_id_id_pk",
- "columns": [
- "workspace_id",
- "id"
- ]
+ "columns": ["workspace_id", "id"]
}
},
"uniqueConstraints": {},
@@ -280,10 +273,7 @@
"compositePrimaryKeys": {
"payment_workspace_id_id_pk": {
"name": "payment_workspace_id_id_pk",
- "columns": [
- "workspace_id",
- "id"
- ]
+ "columns": ["workspace_id", "id"]
}
},
"uniqueConstraints": {},
@@ -398,10 +388,7 @@
"compositePrimaryKeys": {
"usage_workspace_id_id_pk": {
"name": "usage_workspace_id_id_pk",
- "columns": [
- "workspace_id",
- "id"
- ]
+ "columns": ["workspace_id", "id"]
}
},
"uniqueConstraints": {},
@@ -486,17 +473,12 @@
"indexes": {
"global_key": {
"name": "global_key",
- "columns": [
- "key"
- ],
+ "columns": ["key"],
"isUnique": true
},
"name": {
"name": "name",
- "columns": [
- "workspace_id",
- "name"
- ],
+ "columns": ["workspace_id", "name"],
"isUnique": true
}
},
@@ -504,10 +486,7 @@
"compositePrimaryKeys": {
"key_workspace_id_id_pk": {
"name": "key_workspace_id_id_pk",
- "columns": [
- "workspace_id",
- "id"
- ]
+ "columns": ["workspace_id", "id"]
}
},
"uniqueConstraints": {},
@@ -613,32 +592,22 @@
"indexes": {
"user_account_id": {
"name": "user_account_id",
- "columns": [
- "workspace_id",
- "account_id"
- ],
+ "columns": ["workspace_id", "account_id"],
"isUnique": true
},
"user_email": {
"name": "user_email",
- "columns": [
- "workspace_id",
- "email"
- ],
+ "columns": ["workspace_id", "email"],
"isUnique": true
},
"global_account_id": {
"name": "global_account_id",
- "columns": [
- "account_id"
- ],
+ "columns": ["account_id"],
"isUnique": false
},
"global_email": {
"name": "global_email",
- "columns": [
- "email"
- ],
+ "columns": ["email"],
"isUnique": false
}
},
@@ -646,10 +615,7 @@
"compositePrimaryKeys": {
"user_workspace_id_id_pk": {
"name": "user_workspace_id_id_pk",
- "columns": [
- "workspace_id",
- "id"
- ]
+ "columns": ["workspace_id", "id"]
}
},
"uniqueConstraints": {},
@@ -706,9 +672,7 @@
"indexes": {
"slug": {
"name": "slug",
- "columns": [
- "slug"
- ],
+ "columns": ["slug"],
"isUnique": true
}
},
@@ -716,9 +680,7 @@
"compositePrimaryKeys": {
"workspace_id": {
"name": "workspace_id",
- "columns": [
- "id"
- ]
+ "columns": ["id"]
}
},
"uniqueConstraints": {},
@@ -735,4 +697,4 @@
"tables": {},
"indexes": {}
}
-}
\ No newline at end of file
+}
diff --git a/packages/console/core/migrations/meta/0024_snapshot.json b/packages/console/core/migrations/meta/0024_snapshot.json
index 4f50945d..1ef25970 100644
--- a/packages/console/core/migrations/meta/0024_snapshot.json
+++ b/packages/console/core/migrations/meta/0024_snapshot.json
@@ -48,9 +48,7 @@
"indexes": {
"email": {
"name": "email",
- "columns": [
- "email"
- ],
+ "columns": ["email"],
"isUnique": true
}
},
@@ -180,9 +178,7 @@
"indexes": {
"global_customer_id": {
"name": "global_customer_id",
- "columns": [
- "customer_id"
- ],
+ "columns": ["customer_id"],
"isUnique": true
}
},
@@ -190,10 +186,7 @@
"compositePrimaryKeys": {
"billing_workspace_id_id_pk": {
"name": "billing_workspace_id_id_pk",
- "columns": [
- "workspace_id",
- "id"
- ]
+ "columns": ["workspace_id", "id"]
}
},
"uniqueConstraints": {},
@@ -280,10 +273,7 @@
"compositePrimaryKeys": {
"payment_workspace_id_id_pk": {
"name": "payment_workspace_id_id_pk",
- "columns": [
- "workspace_id",
- "id"
- ]
+ "columns": ["workspace_id", "id"]
}
},
"uniqueConstraints": {},
@@ -398,10 +388,7 @@
"compositePrimaryKeys": {
"usage_workspace_id_id_pk": {
"name": "usage_workspace_id_id_pk",
- "columns": [
- "workspace_id",
- "id"
- ]
+ "columns": ["workspace_id", "id"]
}
},
"uniqueConstraints": {},
@@ -486,17 +473,12 @@
"indexes": {
"global_key": {
"name": "global_key",
- "columns": [
- "key"
- ],
+ "columns": ["key"],
"isUnique": true
},
"name": {
"name": "name",
- "columns": [
- "workspace_id",
- "name"
- ],
+ "columns": ["workspace_id", "name"],
"isUnique": true
}
},
@@ -504,10 +486,7 @@
"compositePrimaryKeys": {
"key_workspace_id_id_pk": {
"name": "key_workspace_id_id_pk",
- "columns": [
- "workspace_id",
- "id"
- ]
+ "columns": ["workspace_id", "id"]
}
},
"uniqueConstraints": {},
@@ -599,32 +578,22 @@
"indexes": {
"user_account_id": {
"name": "user_account_id",
- "columns": [
- "workspace_id",
- "account_id"
- ],
+ "columns": ["workspace_id", "account_id"],
"isUnique": true
},
"user_email": {
"name": "user_email",
- "columns": [
- "workspace_id",
- "email"
- ],
+ "columns": ["workspace_id", "email"],
"isUnique": true
},
"global_account_id": {
"name": "global_account_id",
- "columns": [
- "account_id"
- ],
+ "columns": ["account_id"],
"isUnique": false
},
"global_email": {
"name": "global_email",
- "columns": [
- "email"
- ],
+ "columns": ["email"],
"isUnique": false
}
},
@@ -632,10 +601,7 @@
"compositePrimaryKeys": {
"user_workspace_id_id_pk": {
"name": "user_workspace_id_id_pk",
- "columns": [
- "workspace_id",
- "id"
- ]
+ "columns": ["workspace_id", "id"]
}
},
"uniqueConstraints": {},
@@ -692,9 +658,7 @@
"indexes": {
"slug": {
"name": "slug",
- "columns": [
- "slug"
- ],
+ "columns": ["slug"],
"isUnique": true
}
},
@@ -702,9 +666,7 @@
"compositePrimaryKeys": {
"workspace_id": {
"name": "workspace_id",
- "columns": [
- "id"
- ]
+ "columns": ["id"]
}
},
"uniqueConstraints": {},
@@ -721,4 +683,4 @@
"tables": {},
"indexes": {}
}
-}
\ No newline at end of file
+}
diff --git a/packages/console/core/migrations/meta/0025_snapshot.json b/packages/console/core/migrations/meta/0025_snapshot.json
index 4b0cef0c..6746a6e8 100644
--- a/packages/console/core/migrations/meta/0025_snapshot.json
+++ b/packages/console/core/migrations/meta/0025_snapshot.json
@@ -48,9 +48,7 @@
"indexes": {
"email": {
"name": "email",
- "columns": [
- "email"
- ],
+ "columns": ["email"],
"isUnique": true
}
},
@@ -180,9 +178,7 @@
"indexes": {
"global_customer_id": {
"name": "global_customer_id",
- "columns": [
- "customer_id"
- ],
+ "columns": ["customer_id"],
"isUnique": true
}
},
@@ -190,10 +186,7 @@
"compositePrimaryKeys": {
"billing_workspace_id_id_pk": {
"name": "billing_workspace_id_id_pk",
- "columns": [
- "workspace_id",
- "id"
- ]
+ "columns": ["workspace_id", "id"]
}
},
"uniqueConstraints": {},
@@ -280,10 +273,7 @@
"compositePrimaryKeys": {
"payment_workspace_id_id_pk": {
"name": "payment_workspace_id_id_pk",
- "columns": [
- "workspace_id",
- "id"
- ]
+ "columns": ["workspace_id", "id"]
}
},
"uniqueConstraints": {},
@@ -398,10 +388,7 @@
"compositePrimaryKeys": {
"usage_workspace_id_id_pk": {
"name": "usage_workspace_id_id_pk",
- "columns": [
- "workspace_id",
- "id"
- ]
+ "columns": ["workspace_id", "id"]
}
},
"uniqueConstraints": {},
@@ -493,17 +480,12 @@
"indexes": {
"global_key": {
"name": "global_key",
- "columns": [
- "key"
- ],
+ "columns": ["key"],
"isUnique": true
},
"name": {
"name": "name",
- "columns": [
- "workspace_id",
- "name"
- ],
+ "columns": ["workspace_id", "name"],
"isUnique": true
}
},
@@ -511,10 +493,7 @@
"compositePrimaryKeys": {
"key_workspace_id_id_pk": {
"name": "key_workspace_id_id_pk",
- "columns": [
- "workspace_id",
- "id"
- ]
+ "columns": ["workspace_id", "id"]
}
},
"uniqueConstraints": {},
@@ -606,32 +585,22 @@
"indexes": {
"user_account_id": {
"name": "user_account_id",
- "columns": [
- "workspace_id",
- "account_id"
- ],
+ "columns": ["workspace_id", "account_id"],
"isUnique": true
},
"user_email": {
"name": "user_email",
- "columns": [
- "workspace_id",
- "email"
- ],
+ "columns": ["workspace_id", "email"],
"isUnique": true
},
"global_account_id": {
"name": "global_account_id",
- "columns": [
- "account_id"
- ],
+ "columns": ["account_id"],
"isUnique": false
},
"global_email": {
"name": "global_email",
- "columns": [
- "email"
- ],
+ "columns": ["email"],
"isUnique": false
}
},
@@ -639,10 +608,7 @@
"compositePrimaryKeys": {
"user_workspace_id_id_pk": {
"name": "user_workspace_id_id_pk",
- "columns": [
- "workspace_id",
- "id"
- ]
+ "columns": ["workspace_id", "id"]
}
},
"uniqueConstraints": {},
@@ -699,9 +665,7 @@
"indexes": {
"slug": {
"name": "slug",
- "columns": [
- "slug"
- ],
+ "columns": ["slug"],
"isUnique": true
}
},
@@ -709,9 +673,7 @@
"compositePrimaryKeys": {
"workspace_id": {
"name": "workspace_id",
- "columns": [
- "id"
- ]
+ "columns": ["id"]
}
},
"uniqueConstraints": {},
@@ -728,4 +690,4 @@
"tables": {},
"indexes": {}
}
-}
\ No newline at end of file
+}
diff --git a/packages/console/core/migrations/meta/0026_snapshot.json b/packages/console/core/migrations/meta/0026_snapshot.json
index 543ab44c..d3c7dc49 100644
--- a/packages/console/core/migrations/meta/0026_snapshot.json
+++ b/packages/console/core/migrations/meta/0026_snapshot.json
@@ -48,9 +48,7 @@
"indexes": {
"email": {
"name": "email",
- "columns": [
- "email"
- ],
+ "columns": ["email"],
"isUnique": true
}
},
@@ -180,9 +178,7 @@
"indexes": {
"global_customer_id": {
"name": "global_customer_id",
- "columns": [
- "customer_id"
- ],
+ "columns": ["customer_id"],
"isUnique": true
}
},
@@ -190,10 +186,7 @@
"compositePrimaryKeys": {
"billing_workspace_id_id_pk": {
"name": "billing_workspace_id_id_pk",
- "columns": [
- "workspace_id",
- "id"
- ]
+ "columns": ["workspace_id", "id"]
}
},
"uniqueConstraints": {},
@@ -280,10 +273,7 @@
"compositePrimaryKeys": {
"payment_workspace_id_id_pk": {
"name": "payment_workspace_id_id_pk",
- "columns": [
- "workspace_id",
- "id"
- ]
+ "columns": ["workspace_id", "id"]
}
},
"uniqueConstraints": {},
@@ -398,10 +388,7 @@
"compositePrimaryKeys": {
"usage_workspace_id_id_pk": {
"name": "usage_workspace_id_id_pk",
- "columns": [
- "workspace_id",
- "id"
- ]
+ "columns": ["workspace_id", "id"]
}
},
"uniqueConstraints": {},
@@ -493,9 +480,7 @@
"indexes": {
"global_key": {
"name": "global_key",
- "columns": [
- "key"
- ],
+ "columns": ["key"],
"isUnique": true
}
},
@@ -503,10 +488,7 @@
"compositePrimaryKeys": {
"key_workspace_id_id_pk": {
"name": "key_workspace_id_id_pk",
- "columns": [
- "workspace_id",
- "id"
- ]
+ "columns": ["workspace_id", "id"]
}
},
"uniqueConstraints": {},
@@ -598,32 +580,22 @@
"indexes": {
"user_account_id": {
"name": "user_account_id",
- "columns": [
- "workspace_id",
- "account_id"
- ],
+ "columns": ["workspace_id", "account_id"],
"isUnique": true
},
"user_email": {
"name": "user_email",
- "columns": [
- "workspace_id",
- "email"
- ],
+ "columns": ["workspace_id", "email"],
"isUnique": true
},
"global_account_id": {
"name": "global_account_id",
- "columns": [
- "account_id"
- ],
+ "columns": ["account_id"],
"isUnique": false
},
"global_email": {
"name": "global_email",
- "columns": [
- "email"
- ],
+ "columns": ["email"],
"isUnique": false
}
},
@@ -631,10 +603,7 @@
"compositePrimaryKeys": {
"user_workspace_id_id_pk": {
"name": "user_workspace_id_id_pk",
- "columns": [
- "workspace_id",
- "id"
- ]
+ "columns": ["workspace_id", "id"]
}
},
"uniqueConstraints": {},
@@ -691,9 +660,7 @@
"indexes": {
"slug": {
"name": "slug",
- "columns": [
- "slug"
- ],
+ "columns": ["slug"],
"isUnique": true
}
},
@@ -701,9 +668,7 @@
"compositePrimaryKeys": {
"workspace_id": {
"name": "workspace_id",
- "columns": [
- "id"
- ]
+ "columns": ["id"]
}
},
"uniqueConstraints": {},
@@ -720,4 +685,4 @@
"tables": {},
"indexes": {}
}
-}
\ No newline at end of file
+}
diff --git a/packages/console/core/migrations/meta/0027_snapshot.json b/packages/console/core/migrations/meta/0027_snapshot.json
index 9b691022..408766f7 100644
--- a/packages/console/core/migrations/meta/0027_snapshot.json
+++ b/packages/console/core/migrations/meta/0027_snapshot.json
@@ -48,9 +48,7 @@
"indexes": {
"email": {
"name": "email",
- "columns": [
- "email"
- ],
+ "columns": ["email"],
"isUnique": true
}
},
@@ -180,9 +178,7 @@
"indexes": {
"global_customer_id": {
"name": "global_customer_id",
- "columns": [
- "customer_id"
- ],
+ "columns": ["customer_id"],
"isUnique": true
}
},
@@ -190,10 +186,7 @@
"compositePrimaryKeys": {
"billing_workspace_id_id_pk": {
"name": "billing_workspace_id_id_pk",
- "columns": [
- "workspace_id",
- "id"
- ]
+ "columns": ["workspace_id", "id"]
}
},
"uniqueConstraints": {},
@@ -280,10 +273,7 @@
"compositePrimaryKeys": {
"payment_workspace_id_id_pk": {
"name": "payment_workspace_id_id_pk",
- "columns": [
- "workspace_id",
- "id"
- ]
+ "columns": ["workspace_id", "id"]
}
},
"uniqueConstraints": {},
@@ -398,10 +388,7 @@
"compositePrimaryKeys": {
"usage_workspace_id_id_pk": {
"name": "usage_workspace_id_id_pk",
- "columns": [
- "workspace_id",
- "id"
- ]
+ "columns": ["workspace_id", "id"]
}
},
"uniqueConstraints": {},
@@ -479,9 +466,7 @@
"indexes": {
"global_key": {
"name": "global_key",
- "columns": [
- "key"
- ],
+ "columns": ["key"],
"isUnique": true
}
},
@@ -489,10 +474,7 @@
"compositePrimaryKeys": {
"key_workspace_id_id_pk": {
"name": "key_workspace_id_id_pk",
- "columns": [
- "workspace_id",
- "id"
- ]
+ "columns": ["workspace_id", "id"]
}
},
"uniqueConstraints": {},
@@ -584,32 +566,22 @@
"indexes": {
"user_account_id": {
"name": "user_account_id",
- "columns": [
- "workspace_id",
- "account_id"
- ],
+ "columns": ["workspace_id", "account_id"],
"isUnique": true
},
"user_email": {
"name": "user_email",
- "columns": [
- "workspace_id",
- "email"
- ],
+ "columns": ["workspace_id", "email"],
"isUnique": true
},
"global_account_id": {
"name": "global_account_id",
- "columns": [
- "account_id"
- ],
+ "columns": ["account_id"],
"isUnique": false
},
"global_email": {
"name": "global_email",
- "columns": [
- "email"
- ],
+ "columns": ["email"],
"isUnique": false
}
},
@@ -617,10 +589,7 @@
"compositePrimaryKeys": {
"user_workspace_id_id_pk": {
"name": "user_workspace_id_id_pk",
- "columns": [
- "workspace_id",
- "id"
- ]
+ "columns": ["workspace_id", "id"]
}
},
"uniqueConstraints": {},
@@ -677,9 +646,7 @@
"indexes": {
"slug": {
"name": "slug",
- "columns": [
- "slug"
- ],
+ "columns": ["slug"],
"isUnique": true
}
},
@@ -687,9 +654,7 @@
"compositePrimaryKeys": {
"workspace_id": {
"name": "workspace_id",
- "columns": [
- "id"
- ]
+ "columns": ["id"]
}
},
"uniqueConstraints": {},
@@ -706,4 +671,4 @@
"tables": {},
"indexes": {}
}
-}
\ No newline at end of file
+}
diff --git a/packages/console/core/migrations/meta/0028_snapshot.json b/packages/console/core/migrations/meta/0028_snapshot.json
index 8242ae52..827cb53c 100644
--- a/packages/console/core/migrations/meta/0028_snapshot.json
+++ b/packages/console/core/migrations/meta/0028_snapshot.json
@@ -48,9 +48,7 @@
"indexes": {
"email": {
"name": "email",
- "columns": [
- "email"
- ],
+ "columns": ["email"],
"isUnique": true
}
},
@@ -180,9 +178,7 @@
"indexes": {
"global_customer_id": {
"name": "global_customer_id",
- "columns": [
- "customer_id"
- ],
+ "columns": ["customer_id"],
"isUnique": true
}
},
@@ -190,10 +186,7 @@
"compositePrimaryKeys": {
"billing_workspace_id_id_pk": {
"name": "billing_workspace_id_id_pk",
- "columns": [
- "workspace_id",
- "id"
- ]
+ "columns": ["workspace_id", "id"]
}
},
"uniqueConstraints": {},
@@ -280,10 +273,7 @@
"compositePrimaryKeys": {
"payment_workspace_id_id_pk": {
"name": "payment_workspace_id_id_pk",
- "columns": [
- "workspace_id",
- "id"
- ]
+ "columns": ["workspace_id", "id"]
}
},
"uniqueConstraints": {},
@@ -398,10 +388,7 @@
"compositePrimaryKeys": {
"usage_workspace_id_id_pk": {
"name": "usage_workspace_id_id_pk",
- "columns": [
- "workspace_id",
- "id"
- ]
+ "columns": ["workspace_id", "id"]
}
},
"uniqueConstraints": {},
@@ -479,9 +466,7 @@
"indexes": {
"global_key": {
"name": "global_key",
- "columns": [
- "key"
- ],
+ "columns": ["key"],
"isUnique": true
}
},
@@ -489,10 +474,7 @@
"compositePrimaryKeys": {
"key_workspace_id_id_pk": {
"name": "key_workspace_id_id_pk",
- "columns": [
- "workspace_id",
- "id"
- ]
+ "columns": ["workspace_id", "id"]
}
},
"uniqueConstraints": {},
@@ -584,32 +566,22 @@
"indexes": {
"user_account_id": {
"name": "user_account_id",
- "columns": [
- "workspace_id",
- "account_id"
- ],
+ "columns": ["workspace_id", "account_id"],
"isUnique": true
},
"user_email": {
"name": "user_email",
- "columns": [
- "workspace_id",
- "email"
- ],
+ "columns": ["workspace_id", "email"],
"isUnique": true
},
"global_account_id": {
"name": "global_account_id",
- "columns": [
- "account_id"
- ],
+ "columns": ["account_id"],
"isUnique": false
},
"global_email": {
"name": "global_email",
- "columns": [
- "email"
- ],
+ "columns": ["email"],
"isUnique": false
}
},
@@ -617,10 +589,7 @@
"compositePrimaryKeys": {
"user_workspace_id_id_pk": {
"name": "user_workspace_id_id_pk",
- "columns": [
- "workspace_id",
- "id"
- ]
+ "columns": ["workspace_id", "id"]
}
},
"uniqueConstraints": {},
@@ -677,9 +646,7 @@
"indexes": {
"slug": {
"name": "slug",
- "columns": [
- "slug"
- ],
+ "columns": ["slug"],
"isUnique": true
}
},
@@ -687,9 +654,7 @@
"compositePrimaryKeys": {
"workspace_id": {
"name": "workspace_id",
- "columns": [
- "id"
- ]
+ "columns": ["id"]
}
},
"uniqueConstraints": {},
@@ -706,4 +671,4 @@
"tables": {},
"indexes": {}
}
-}
\ No newline at end of file
+}
diff --git a/packages/console/core/migrations/meta/0029_snapshot.json b/packages/console/core/migrations/meta/0029_snapshot.json
index 959004f3..d235697c 100644
--- a/packages/console/core/migrations/meta/0029_snapshot.json
+++ b/packages/console/core/migrations/meta/0029_snapshot.json
@@ -48,9 +48,7 @@
"indexes": {
"email": {
"name": "email",
- "columns": [
- "email"
- ],
+ "columns": ["email"],
"isUnique": true
}
},
@@ -180,9 +178,7 @@
"indexes": {
"global_customer_id": {
"name": "global_customer_id",
- "columns": [
- "customer_id"
- ],
+ "columns": ["customer_id"],
"isUnique": true
}
},
@@ -190,10 +186,7 @@
"compositePrimaryKeys": {
"billing_workspace_id_id_pk": {
"name": "billing_workspace_id_id_pk",
- "columns": [
- "workspace_id",
- "id"
- ]
+ "columns": ["workspace_id", "id"]
}
},
"uniqueConstraints": {},
@@ -280,10 +273,7 @@
"compositePrimaryKeys": {
"payment_workspace_id_id_pk": {
"name": "payment_workspace_id_id_pk",
- "columns": [
- "workspace_id",
- "id"
- ]
+ "columns": ["workspace_id", "id"]
}
},
"uniqueConstraints": {},
@@ -398,10 +388,7 @@
"compositePrimaryKeys": {
"usage_workspace_id_id_pk": {
"name": "usage_workspace_id_id_pk",
- "columns": [
- "workspace_id",
- "id"
- ]
+ "columns": ["workspace_id", "id"]
}
},
"uniqueConstraints": {},
@@ -479,9 +466,7 @@
"indexes": {
"global_key": {
"name": "global_key",
- "columns": [
- "key"
- ],
+ "columns": ["key"],
"isUnique": true
}
},
@@ -489,10 +474,7 @@
"compositePrimaryKeys": {
"key_workspace_id_id_pk": {
"name": "key_workspace_id_id_pk",
- "columns": [
- "workspace_id",
- "id"
- ]
+ "columns": ["workspace_id", "id"]
}
},
"uniqueConstraints": {},
@@ -605,32 +587,22 @@
"indexes": {
"user_account_id": {
"name": "user_account_id",
- "columns": [
- "workspace_id",
- "account_id"
- ],
+ "columns": ["workspace_id", "account_id"],
"isUnique": true
},
"user_email": {
"name": "user_email",
- "columns": [
- "workspace_id",
- "email"
- ],
+ "columns": ["workspace_id", "email"],
"isUnique": true
},
"global_account_id": {
"name": "global_account_id",
- "columns": [
- "account_id"
- ],
+ "columns": ["account_id"],
"isUnique": false
},
"global_email": {
"name": "global_email",
- "columns": [
- "email"
- ],
+ "columns": ["email"],
"isUnique": false
}
},
@@ -638,10 +610,7 @@
"compositePrimaryKeys": {
"user_workspace_id_id_pk": {
"name": "user_workspace_id_id_pk",
- "columns": [
- "workspace_id",
- "id"
- ]
+ "columns": ["workspace_id", "id"]
}
},
"uniqueConstraints": {},
@@ -698,9 +667,7 @@
"indexes": {
"slug": {
"name": "slug",
- "columns": [
- "slug"
- ],
+ "columns": ["slug"],
"isUnique": true
}
},
@@ -708,9 +675,7 @@
"compositePrimaryKeys": {
"workspace_id": {
"name": "workspace_id",
- "columns": [
- "id"
- ]
+ "columns": ["id"]
}
},
"uniqueConstraints": {},
@@ -727,4 +692,4 @@
"tables": {},
"indexes": {}
}
-}
\ No newline at end of file
+}
diff --git a/packages/console/core/migrations/meta/0030_snapshot.json b/packages/console/core/migrations/meta/0030_snapshot.json
index 6a6eb38c..66978dfa 100644
--- a/packages/console/core/migrations/meta/0030_snapshot.json
+++ b/packages/console/core/migrations/meta/0030_snapshot.json
@@ -48,9 +48,7 @@
"indexes": {
"email": {
"name": "email",
- "columns": [
- "email"
- ],
+ "columns": ["email"],
"isUnique": true
}
},
@@ -180,9 +178,7 @@
"indexes": {
"global_customer_id": {
"name": "global_customer_id",
- "columns": [
- "customer_id"
- ],
+ "columns": ["customer_id"],
"isUnique": true
}
},
@@ -190,10 +186,7 @@
"compositePrimaryKeys": {
"billing_workspace_id_id_pk": {
"name": "billing_workspace_id_id_pk",
- "columns": [
- "workspace_id",
- "id"
- ]
+ "columns": ["workspace_id", "id"]
}
},
"uniqueConstraints": {},
@@ -280,10 +273,7 @@
"compositePrimaryKeys": {
"payment_workspace_id_id_pk": {
"name": "payment_workspace_id_id_pk",
- "columns": [
- "workspace_id",
- "id"
- ]
+ "columns": ["workspace_id", "id"]
}
},
"uniqueConstraints": {},
@@ -398,10 +388,7 @@
"compositePrimaryKeys": {
"usage_workspace_id_id_pk": {
"name": "usage_workspace_id_id_pk",
- "columns": [
- "workspace_id",
- "id"
- ]
+ "columns": ["workspace_id", "id"]
}
},
"uniqueConstraints": {},
@@ -479,9 +466,7 @@
"indexes": {
"global_key": {
"name": "global_key",
- "columns": [
- "key"
- ],
+ "columns": ["key"],
"isUnique": true
}
},
@@ -489,10 +474,7 @@
"compositePrimaryKeys": {
"key_workspace_id_id_pk": {
"name": "key_workspace_id_id_pk",
- "columns": [
- "workspace_id",
- "id"
- ]
+ "columns": ["workspace_id", "id"]
}
},
"uniqueConstraints": {},
@@ -549,10 +531,7 @@
"indexes": {
"model_workspace_model": {
"name": "model_workspace_model",
- "columns": [
- "workspace_id",
- "model"
- ],
+ "columns": ["workspace_id", "model"],
"isUnique": true
}
},
@@ -560,10 +539,7 @@
"compositePrimaryKeys": {
"model_workspace_id_id_pk": {
"name": "model_workspace_id_id_pk",
- "columns": [
- "workspace_id",
- "id"
- ]
+ "columns": ["workspace_id", "id"]
}
},
"uniqueConstraints": {},
@@ -676,32 +652,22 @@
"indexes": {
"user_account_id": {
"name": "user_account_id",
- "columns": [
- "workspace_id",
- "account_id"
- ],
+ "columns": ["workspace_id", "account_id"],
"isUnique": true
},
"user_email": {
"name": "user_email",
- "columns": [
- "workspace_id",
- "email"
- ],
+ "columns": ["workspace_id", "email"],
"isUnique": true
},
"global_account_id": {
"name": "global_account_id",
- "columns": [
- "account_id"
- ],
+ "columns": ["account_id"],
"isUnique": false
},
"global_email": {
"name": "global_email",
- "columns": [
- "email"
- ],
+ "columns": ["email"],
"isUnique": false
}
},
@@ -709,10 +675,7 @@
"compositePrimaryKeys": {
"user_workspace_id_id_pk": {
"name": "user_workspace_id_id_pk",
- "columns": [
- "workspace_id",
- "id"
- ]
+ "columns": ["workspace_id", "id"]
}
},
"uniqueConstraints": {},
@@ -769,9 +732,7 @@
"indexes": {
"slug": {
"name": "slug",
- "columns": [
- "slug"
- ],
+ "columns": ["slug"],
"isUnique": true
}
},
@@ -779,9 +740,7 @@
"compositePrimaryKeys": {
"workspace_id": {
"name": "workspace_id",
- "columns": [
- "id"
- ]
+ "columns": ["id"]
}
},
"uniqueConstraints": {},
@@ -798,4 +757,4 @@
"tables": {},
"indexes": {}
}
-}
\ No newline at end of file
+}
diff --git a/packages/console/core/migrations/meta/0031_snapshot.json b/packages/console/core/migrations/meta/0031_snapshot.json
index ba964881..c4716592 100644
--- a/packages/console/core/migrations/meta/0031_snapshot.json
+++ b/packages/console/core/migrations/meta/0031_snapshot.json
@@ -48,9 +48,7 @@
"indexes": {
"email": {
"name": "email",
- "columns": [
- "email"
- ],
+ "columns": ["email"],
"isUnique": true
}
},
@@ -180,9 +178,7 @@
"indexes": {
"global_customer_id": {
"name": "global_customer_id",
- "columns": [
- "customer_id"
- ],
+ "columns": ["customer_id"],
"isUnique": true
}
},
@@ -190,10 +186,7 @@
"compositePrimaryKeys": {
"billing_workspace_id_id_pk": {
"name": "billing_workspace_id_id_pk",
- "columns": [
- "workspace_id",
- "id"
- ]
+ "columns": ["workspace_id", "id"]
}
},
"uniqueConstraints": {},
@@ -280,10 +273,7 @@
"compositePrimaryKeys": {
"payment_workspace_id_id_pk": {
"name": "payment_workspace_id_id_pk",
- "columns": [
- "workspace_id",
- "id"
- ]
+ "columns": ["workspace_id", "id"]
}
},
"uniqueConstraints": {},
@@ -398,10 +388,7 @@
"compositePrimaryKeys": {
"usage_workspace_id_id_pk": {
"name": "usage_workspace_id_id_pk",
- "columns": [
- "workspace_id",
- "id"
- ]
+ "columns": ["workspace_id", "id"]
}
},
"uniqueConstraints": {},
@@ -479,9 +466,7 @@
"indexes": {
"global_key": {
"name": "global_key",
- "columns": [
- "key"
- ],
+ "columns": ["key"],
"isUnique": true
}
},
@@ -489,10 +474,7 @@
"compositePrimaryKeys": {
"key_workspace_id_id_pk": {
"name": "key_workspace_id_id_pk",
- "columns": [
- "workspace_id",
- "id"
- ]
+ "columns": ["workspace_id", "id"]
}
},
"uniqueConstraints": {},
@@ -549,10 +531,7 @@
"indexes": {
"model_workspace_model": {
"name": "model_workspace_model",
- "columns": [
- "workspace_id",
- "model"
- ],
+ "columns": ["workspace_id", "model"],
"isUnique": true
}
},
@@ -560,10 +539,7 @@
"compositePrimaryKeys": {
"model_workspace_id_id_pk": {
"name": "model_workspace_id_id_pk",
- "columns": [
- "workspace_id",
- "id"
- ]
+ "columns": ["workspace_id", "id"]
}
},
"uniqueConstraints": {},
@@ -627,10 +603,7 @@
"indexes": {
"workspace_provider": {
"name": "workspace_provider",
- "columns": [
- "workspace_id",
- "provider"
- ],
+ "columns": ["workspace_id", "provider"],
"isUnique": true
}
},
@@ -638,10 +611,7 @@
"compositePrimaryKeys": {
"provider_workspace_id_id_pk": {
"name": "provider_workspace_id_id_pk",
- "columns": [
- "workspace_id",
- "id"
- ]
+ "columns": ["workspace_id", "id"]
}
},
"uniqueConstraints": {},
@@ -754,32 +724,22 @@
"indexes": {
"user_account_id": {
"name": "user_account_id",
- "columns": [
- "workspace_id",
- "account_id"
- ],
+ "columns": ["workspace_id", "account_id"],
"isUnique": true
},
"user_email": {
"name": "user_email",
- "columns": [
- "workspace_id",
- "email"
- ],
+ "columns": ["workspace_id", "email"],
"isUnique": true
},
"global_account_id": {
"name": "global_account_id",
- "columns": [
- "account_id"
- ],
+ "columns": ["account_id"],
"isUnique": false
},
"global_email": {
"name": "global_email",
- "columns": [
- "email"
- ],
+ "columns": ["email"],
"isUnique": false
}
},
@@ -787,10 +747,7 @@
"compositePrimaryKeys": {
"user_workspace_id_id_pk": {
"name": "user_workspace_id_id_pk",
- "columns": [
- "workspace_id",
- "id"
- ]
+ "columns": ["workspace_id", "id"]
}
},
"uniqueConstraints": {},
@@ -847,9 +804,7 @@
"indexes": {
"slug": {
"name": "slug",
- "columns": [
- "slug"
- ],
+ "columns": ["slug"],
"isUnique": true
}
},
@@ -857,9 +812,7 @@
"compositePrimaryKeys": {
"workspace_id": {
"name": "workspace_id",
- "columns": [
- "id"
- ]
+ "columns": ["id"]
}
},
"uniqueConstraints": {},
@@ -876,4 +829,4 @@
"tables": {},
"indexes": {}
}
-}
\ No newline at end of file
+}
diff --git a/packages/console/core/migrations/meta/0032_snapshot.json b/packages/console/core/migrations/meta/0032_snapshot.json
index 344fde6f..51e84a1d 100644
--- a/packages/console/core/migrations/meta/0032_snapshot.json
+++ b/packages/console/core/migrations/meta/0032_snapshot.json
@@ -48,9 +48,7 @@
"indexes": {
"email": {
"name": "email",
- "columns": [
- "email"
- ],
+ "columns": ["email"],
"isUnique": true
}
},
@@ -180,9 +178,7 @@
"indexes": {
"global_customer_id": {
"name": "global_customer_id",
- "columns": [
- "customer_id"
- ],
+ "columns": ["customer_id"],
"isUnique": true
}
},
@@ -190,10 +186,7 @@
"compositePrimaryKeys": {
"billing_workspace_id_id_pk": {
"name": "billing_workspace_id_id_pk",
- "columns": [
- "workspace_id",
- "id"
- ]
+ "columns": ["workspace_id", "id"]
}
},
"uniqueConstraints": {},
@@ -280,10 +273,7 @@
"compositePrimaryKeys": {
"payment_workspace_id_id_pk": {
"name": "payment_workspace_id_id_pk",
- "columns": [
- "workspace_id",
- "id"
- ]
+ "columns": ["workspace_id", "id"]
}
},
"uniqueConstraints": {},
@@ -405,10 +395,7 @@
"compositePrimaryKeys": {
"usage_workspace_id_id_pk": {
"name": "usage_workspace_id_id_pk",
- "columns": [
- "workspace_id",
- "id"
- ]
+ "columns": ["workspace_id", "id"]
}
},
"uniqueConstraints": {},
@@ -486,9 +473,7 @@
"indexes": {
"global_key": {
"name": "global_key",
- "columns": [
- "key"
- ],
+ "columns": ["key"],
"isUnique": true
}
},
@@ -496,10 +481,7 @@
"compositePrimaryKeys": {
"key_workspace_id_id_pk": {
"name": "key_workspace_id_id_pk",
- "columns": [
- "workspace_id",
- "id"
- ]
+ "columns": ["workspace_id", "id"]
}
},
"uniqueConstraints": {},
@@ -556,10 +538,7 @@
"indexes": {
"model_workspace_model": {
"name": "model_workspace_model",
- "columns": [
- "workspace_id",
- "model"
- ],
+ "columns": ["workspace_id", "model"],
"isUnique": true
}
},
@@ -567,10 +546,7 @@
"compositePrimaryKeys": {
"model_workspace_id_id_pk": {
"name": "model_workspace_id_id_pk",
- "columns": [
- "workspace_id",
- "id"
- ]
+ "columns": ["workspace_id", "id"]
}
},
"uniqueConstraints": {},
@@ -634,10 +610,7 @@
"indexes": {
"workspace_provider": {
"name": "workspace_provider",
- "columns": [
- "workspace_id",
- "provider"
- ],
+ "columns": ["workspace_id", "provider"],
"isUnique": true
}
},
@@ -645,10 +618,7 @@
"compositePrimaryKeys": {
"provider_workspace_id_id_pk": {
"name": "provider_workspace_id_id_pk",
- "columns": [
- "workspace_id",
- "id"
- ]
+ "columns": ["workspace_id", "id"]
}
},
"uniqueConstraints": {},
@@ -761,32 +731,22 @@
"indexes": {
"user_account_id": {
"name": "user_account_id",
- "columns": [
- "workspace_id",
- "account_id"
- ],
+ "columns": ["workspace_id", "account_id"],
"isUnique": true
},
"user_email": {
"name": "user_email",
- "columns": [
- "workspace_id",
- "email"
- ],
+ "columns": ["workspace_id", "email"],
"isUnique": true
},
"global_account_id": {
"name": "global_account_id",
- "columns": [
- "account_id"
- ],
+ "columns": ["account_id"],
"isUnique": false
},
"global_email": {
"name": "global_email",
- "columns": [
- "email"
- ],
+ "columns": ["email"],
"isUnique": false
}
},
@@ -794,10 +754,7 @@
"compositePrimaryKeys": {
"user_workspace_id_id_pk": {
"name": "user_workspace_id_id_pk",
- "columns": [
- "workspace_id",
- "id"
- ]
+ "columns": ["workspace_id", "id"]
}
},
"uniqueConstraints": {},
@@ -854,9 +811,7 @@
"indexes": {
"slug": {
"name": "slug",
- "columns": [
- "slug"
- ],
+ "columns": ["slug"],
"isUnique": true
}
},
@@ -864,9 +819,7 @@
"compositePrimaryKeys": {
"workspace_id": {
"name": "workspace_id",
- "columns": [
- "id"
- ]
+ "columns": ["id"]
}
},
"uniqueConstraints": {},
@@ -883,4 +836,4 @@
"tables": {},
"indexes": {}
}
-}
\ No newline at end of file
+}
diff --git a/packages/console/core/migrations/meta/0033_snapshot.json b/packages/console/core/migrations/meta/0033_snapshot.json
index eb682adc..76d4720e 100644
--- a/packages/console/core/migrations/meta/0033_snapshot.json
+++ b/packages/console/core/migrations/meta/0033_snapshot.json
@@ -48,9 +48,7 @@
"indexes": {
"email": {
"name": "email",
- "columns": [
- "email"
- ],
+ "columns": ["email"],
"isUnique": true
}
},
@@ -187,9 +185,7 @@
"indexes": {
"global_customer_id": {
"name": "global_customer_id",
- "columns": [
- "customer_id"
- ],
+ "columns": ["customer_id"],
"isUnique": true
}
},
@@ -197,10 +193,7 @@
"compositePrimaryKeys": {
"billing_workspace_id_id_pk": {
"name": "billing_workspace_id_id_pk",
- "columns": [
- "workspace_id",
- "id"
- ]
+ "columns": ["workspace_id", "id"]
}
},
"uniqueConstraints": {},
@@ -287,10 +280,7 @@
"compositePrimaryKeys": {
"payment_workspace_id_id_pk": {
"name": "payment_workspace_id_id_pk",
- "columns": [
- "workspace_id",
- "id"
- ]
+ "columns": ["workspace_id", "id"]
}
},
"uniqueConstraints": {},
@@ -412,10 +402,7 @@
"compositePrimaryKeys": {
"usage_workspace_id_id_pk": {
"name": "usage_workspace_id_id_pk",
- "columns": [
- "workspace_id",
- "id"
- ]
+ "columns": ["workspace_id", "id"]
}
},
"uniqueConstraints": {},
@@ -493,9 +480,7 @@
"indexes": {
"global_key": {
"name": "global_key",
- "columns": [
- "key"
- ],
+ "columns": ["key"],
"isUnique": true
}
},
@@ -503,10 +488,7 @@
"compositePrimaryKeys": {
"key_workspace_id_id_pk": {
"name": "key_workspace_id_id_pk",
- "columns": [
- "workspace_id",
- "id"
- ]
+ "columns": ["workspace_id", "id"]
}
},
"uniqueConstraints": {},
@@ -563,10 +545,7 @@
"indexes": {
"model_workspace_model": {
"name": "model_workspace_model",
- "columns": [
- "workspace_id",
- "model"
- ],
+ "columns": ["workspace_id", "model"],
"isUnique": true
}
},
@@ -574,10 +553,7 @@
"compositePrimaryKeys": {
"model_workspace_id_id_pk": {
"name": "model_workspace_id_id_pk",
- "columns": [
- "workspace_id",
- "id"
- ]
+ "columns": ["workspace_id", "id"]
}
},
"uniqueConstraints": {},
@@ -641,10 +617,7 @@
"indexes": {
"workspace_provider": {
"name": "workspace_provider",
- "columns": [
- "workspace_id",
- "provider"
- ],
+ "columns": ["workspace_id", "provider"],
"isUnique": true
}
},
@@ -652,10 +625,7 @@
"compositePrimaryKeys": {
"provider_workspace_id_id_pk": {
"name": "provider_workspace_id_id_pk",
- "columns": [
- "workspace_id",
- "id"
- ]
+ "columns": ["workspace_id", "id"]
}
},
"uniqueConstraints": {},
@@ -768,32 +738,22 @@
"indexes": {
"user_account_id": {
"name": "user_account_id",
- "columns": [
- "workspace_id",
- "account_id"
- ],
+ "columns": ["workspace_id", "account_id"],
"isUnique": true
},
"user_email": {
"name": "user_email",
- "columns": [
- "workspace_id",
- "email"
- ],
+ "columns": ["workspace_id", "email"],
"isUnique": true
},
"global_account_id": {
"name": "global_account_id",
- "columns": [
- "account_id"
- ],
+ "columns": ["account_id"],
"isUnique": false
},
"global_email": {
"name": "global_email",
- "columns": [
- "email"
- ],
+ "columns": ["email"],
"isUnique": false
}
},
@@ -801,10 +761,7 @@
"compositePrimaryKeys": {
"user_workspace_id_id_pk": {
"name": "user_workspace_id_id_pk",
- "columns": [
- "workspace_id",
- "id"
- ]
+ "columns": ["workspace_id", "id"]
}
},
"uniqueConstraints": {},
@@ -861,9 +818,7 @@
"indexes": {
"slug": {
"name": "slug",
- "columns": [
- "slug"
- ],
+ "columns": ["slug"],
"isUnique": true
}
},
@@ -871,9 +826,7 @@
"compositePrimaryKeys": {
"workspace_id": {
"name": "workspace_id",
- "columns": [
- "id"
- ]
+ "columns": ["id"]
}
},
"uniqueConstraints": {},
@@ -890,4 +843,4 @@
"tables": {},
"indexes": {}
}
-}
\ No newline at end of file
+}
diff --git a/packages/console/core/migrations/meta/0034_snapshot.json b/packages/console/core/migrations/meta/0034_snapshot.json
index 36acbdef..e9c999be 100644
--- a/packages/console/core/migrations/meta/0034_snapshot.json
+++ b/packages/console/core/migrations/meta/0034_snapshot.json
@@ -48,9 +48,7 @@
"indexes": {
"email": {
"name": "email",
- "columns": [
- "email"
- ],
+ "columns": ["email"],
"isUnique": true
}
},
@@ -117,10 +115,7 @@
"indexes": {
"provider": {
"name": "provider",
- "columns": [
- "provider",
- "subject"
- ],
+ "columns": ["provider", "subject"],
"isUnique": true
}
},
@@ -257,9 +252,7 @@
"indexes": {
"global_customer_id": {
"name": "global_customer_id",
- "columns": [
- "customer_id"
- ],
+ "columns": ["customer_id"],
"isUnique": true
}
},
@@ -267,10 +260,7 @@
"compositePrimaryKeys": {
"billing_workspace_id_id_pk": {
"name": "billing_workspace_id_id_pk",
- "columns": [
- "workspace_id",
- "id"
- ]
+ "columns": ["workspace_id", "id"]
}
},
"uniqueConstraints": {},
@@ -357,10 +347,7 @@
"compositePrimaryKeys": {
"payment_workspace_id_id_pk": {
"name": "payment_workspace_id_id_pk",
- "columns": [
- "workspace_id",
- "id"
- ]
+ "columns": ["workspace_id", "id"]
}
},
"uniqueConstraints": {},
@@ -482,10 +469,7 @@
"compositePrimaryKeys": {
"usage_workspace_id_id_pk": {
"name": "usage_workspace_id_id_pk",
- "columns": [
- "workspace_id",
- "id"
- ]
+ "columns": ["workspace_id", "id"]
}
},
"uniqueConstraints": {},
@@ -563,9 +547,7 @@
"indexes": {
"global_key": {
"name": "global_key",
- "columns": [
- "key"
- ],
+ "columns": ["key"],
"isUnique": true
}
},
@@ -573,10 +555,7 @@
"compositePrimaryKeys": {
"key_workspace_id_id_pk": {
"name": "key_workspace_id_id_pk",
- "columns": [
- "workspace_id",
- "id"
- ]
+ "columns": ["workspace_id", "id"]
}
},
"uniqueConstraints": {},
@@ -633,10 +612,7 @@
"indexes": {
"model_workspace_model": {
"name": "model_workspace_model",
- "columns": [
- "workspace_id",
- "model"
- ],
+ "columns": ["workspace_id", "model"],
"isUnique": true
}
},
@@ -644,10 +620,7 @@
"compositePrimaryKeys": {
"model_workspace_id_id_pk": {
"name": "model_workspace_id_id_pk",
- "columns": [
- "workspace_id",
- "id"
- ]
+ "columns": ["workspace_id", "id"]
}
},
"uniqueConstraints": {},
@@ -711,10 +684,7 @@
"indexes": {
"workspace_provider": {
"name": "workspace_provider",
- "columns": [
- "workspace_id",
- "provider"
- ],
+ "columns": ["workspace_id", "provider"],
"isUnique": true
}
},
@@ -722,10 +692,7 @@
"compositePrimaryKeys": {
"provider_workspace_id_id_pk": {
"name": "provider_workspace_id_id_pk",
- "columns": [
- "workspace_id",
- "id"
- ]
+ "columns": ["workspace_id", "id"]
}
},
"uniqueConstraints": {},
@@ -838,32 +805,22 @@
"indexes": {
"user_account_id": {
"name": "user_account_id",
- "columns": [
- "workspace_id",
- "account_id"
- ],
+ "columns": ["workspace_id", "account_id"],
"isUnique": true
},
"user_email": {
"name": "user_email",
- "columns": [
- "workspace_id",
- "email"
- ],
+ "columns": ["workspace_id", "email"],
"isUnique": true
},
"global_account_id": {
"name": "global_account_id",
- "columns": [
- "account_id"
- ],
+ "columns": ["account_id"],
"isUnique": false
},
"global_email": {
"name": "global_email",
- "columns": [
- "email"
- ],
+ "columns": ["email"],
"isUnique": false
}
},
@@ -871,10 +828,7 @@
"compositePrimaryKeys": {
"user_workspace_id_id_pk": {
"name": "user_workspace_id_id_pk",
- "columns": [
- "workspace_id",
- "id"
- ]
+ "columns": ["workspace_id", "id"]
}
},
"uniqueConstraints": {},
@@ -931,9 +885,7 @@
"indexes": {
"slug": {
"name": "slug",
- "columns": [
- "slug"
- ],
+ "columns": ["slug"],
"isUnique": true
}
},
@@ -941,9 +893,7 @@
"compositePrimaryKeys": {
"workspace_id": {
"name": "workspace_id",
- "columns": [
- "id"
- ]
+ "columns": ["id"]
}
},
"uniqueConstraints": {},
@@ -960,4 +910,4 @@
"tables": {},
"indexes": {}
}
-}
\ No newline at end of file
+}
diff --git a/packages/console/core/migrations/meta/0035_snapshot.json b/packages/console/core/migrations/meta/0035_snapshot.json
index 7478337b..815d120e 100644
--- a/packages/console/core/migrations/meta/0035_snapshot.json
+++ b/packages/console/core/migrations/meta/0035_snapshot.json
@@ -102,17 +102,12 @@
"indexes": {
"provider": {
"name": "provider",
- "columns": [
- "provider",
- "subject"
- ],
+ "columns": ["provider", "subject"],
"isUnique": true
},
"account_id": {
"name": "account_id",
- "columns": [
- "account_id"
- ],
+ "columns": ["account_id"],
"isUnique": false
}
},
@@ -249,9 +244,7 @@
"indexes": {
"global_customer_id": {
"name": "global_customer_id",
- "columns": [
- "customer_id"
- ],
+ "columns": ["customer_id"],
"isUnique": true
}
},
@@ -259,10 +252,7 @@
"compositePrimaryKeys": {
"billing_workspace_id_id_pk": {
"name": "billing_workspace_id_id_pk",
- "columns": [
- "workspace_id",
- "id"
- ]
+ "columns": ["workspace_id", "id"]
}
},
"uniqueConstraints": {},
@@ -349,10 +339,7 @@
"compositePrimaryKeys": {
"payment_workspace_id_id_pk": {
"name": "payment_workspace_id_id_pk",
- "columns": [
- "workspace_id",
- "id"
- ]
+ "columns": ["workspace_id", "id"]
}
},
"uniqueConstraints": {},
@@ -474,10 +461,7 @@
"compositePrimaryKeys": {
"usage_workspace_id_id_pk": {
"name": "usage_workspace_id_id_pk",
- "columns": [
- "workspace_id",
- "id"
- ]
+ "columns": ["workspace_id", "id"]
}
},
"uniqueConstraints": {},
@@ -555,9 +539,7 @@
"indexes": {
"global_key": {
"name": "global_key",
- "columns": [
- "key"
- ],
+ "columns": ["key"],
"isUnique": true
}
},
@@ -565,10 +547,7 @@
"compositePrimaryKeys": {
"key_workspace_id_id_pk": {
"name": "key_workspace_id_id_pk",
- "columns": [
- "workspace_id",
- "id"
- ]
+ "columns": ["workspace_id", "id"]
}
},
"uniqueConstraints": {},
@@ -625,10 +604,7 @@
"indexes": {
"model_workspace_model": {
"name": "model_workspace_model",
- "columns": [
- "workspace_id",
- "model"
- ],
+ "columns": ["workspace_id", "model"],
"isUnique": true
}
},
@@ -636,10 +612,7 @@
"compositePrimaryKeys": {
"model_workspace_id_id_pk": {
"name": "model_workspace_id_id_pk",
- "columns": [
- "workspace_id",
- "id"
- ]
+ "columns": ["workspace_id", "id"]
}
},
"uniqueConstraints": {},
@@ -703,10 +676,7 @@
"indexes": {
"workspace_provider": {
"name": "workspace_provider",
- "columns": [
- "workspace_id",
- "provider"
- ],
+ "columns": ["workspace_id", "provider"],
"isUnique": true
}
},
@@ -714,10 +684,7 @@
"compositePrimaryKeys": {
"provider_workspace_id_id_pk": {
"name": "provider_workspace_id_id_pk",
- "columns": [
- "workspace_id",
- "id"
- ]
+ "columns": ["workspace_id", "id"]
}
},
"uniqueConstraints": {},
@@ -830,32 +797,22 @@
"indexes": {
"user_account_id": {
"name": "user_account_id",
- "columns": [
- "workspace_id",
- "account_id"
- ],
+ "columns": ["workspace_id", "account_id"],
"isUnique": true
},
"user_email": {
"name": "user_email",
- "columns": [
- "workspace_id",
- "email"
- ],
+ "columns": ["workspace_id", "email"],
"isUnique": true
},
"global_account_id": {
"name": "global_account_id",
- "columns": [
- "account_id"
- ],
+ "columns": ["account_id"],
"isUnique": false
},
"global_email": {
"name": "global_email",
- "columns": [
- "email"
- ],
+ "columns": ["email"],
"isUnique": false
}
},
@@ -863,10 +820,7 @@
"compositePrimaryKeys": {
"user_workspace_id_id_pk": {
"name": "user_workspace_id_id_pk",
- "columns": [
- "workspace_id",
- "id"
- ]
+ "columns": ["workspace_id", "id"]
}
},
"uniqueConstraints": {},
@@ -923,9 +877,7 @@
"indexes": {
"slug": {
"name": "slug",
- "columns": [
- "slug"
- ],
+ "columns": ["slug"],
"isUnique": true
}
},
@@ -933,9 +885,7 @@
"compositePrimaryKeys": {
"workspace_id": {
"name": "workspace_id",
- "columns": [
- "id"
- ]
+ "columns": ["id"]
}
},
"uniqueConstraints": {},
@@ -952,4 +902,4 @@
"tables": {},
"indexes": {}
}
-}
\ No newline at end of file
+}
diff --git a/packages/console/core/migrations/meta/0036_snapshot.json b/packages/console/core/migrations/meta/0036_snapshot.json
index b030e30e..926b143e 100644
--- a/packages/console/core/migrations/meta/0036_snapshot.json
+++ b/packages/console/core/migrations/meta/0036_snapshot.json
@@ -43,9 +43,7 @@
"compositePrimaryKeys": {
"account_id_pk": {
"name": "account_id_pk",
- "columns": [
- "id"
- ]
+ "columns": ["id"]
}
},
"uniqueConstraints": {},
@@ -109,17 +107,12 @@
"indexes": {
"provider": {
"name": "provider",
- "columns": [
- "provider",
- "subject"
- ],
+ "columns": ["provider", "subject"],
"isUnique": true
},
"account_id": {
"name": "account_id",
- "columns": [
- "account_id"
- ],
+ "columns": ["account_id"],
"isUnique": false
}
},
@@ -127,9 +120,7 @@
"compositePrimaryKeys": {
"auth_id_pk": {
"name": "auth_id_pk",
- "columns": [
- "id"
- ]
+ "columns": ["id"]
}
},
"uniqueConstraints": {},
@@ -263,9 +254,7 @@
"indexes": {
"global_customer_id": {
"name": "global_customer_id",
- "columns": [
- "customer_id"
- ],
+ "columns": ["customer_id"],
"isUnique": true
}
},
@@ -273,10 +262,7 @@
"compositePrimaryKeys": {
"billing_workspace_id_id_pk": {
"name": "billing_workspace_id_id_pk",
- "columns": [
- "workspace_id",
- "id"
- ]
+ "columns": ["workspace_id", "id"]
}
},
"uniqueConstraints": {},
@@ -363,10 +349,7 @@
"compositePrimaryKeys": {
"payment_workspace_id_id_pk": {
"name": "payment_workspace_id_id_pk",
- "columns": [
- "workspace_id",
- "id"
- ]
+ "columns": ["workspace_id", "id"]
}
},
"uniqueConstraints": {},
@@ -488,10 +471,7 @@
"compositePrimaryKeys": {
"usage_workspace_id_id_pk": {
"name": "usage_workspace_id_id_pk",
- "columns": [
- "workspace_id",
- "id"
- ]
+ "columns": ["workspace_id", "id"]
}
},
"uniqueConstraints": {},
@@ -569,9 +549,7 @@
"indexes": {
"global_key": {
"name": "global_key",
- "columns": [
- "key"
- ],
+ "columns": ["key"],
"isUnique": true
}
},
@@ -579,10 +557,7 @@
"compositePrimaryKeys": {
"key_workspace_id_id_pk": {
"name": "key_workspace_id_id_pk",
- "columns": [
- "workspace_id",
- "id"
- ]
+ "columns": ["workspace_id", "id"]
}
},
"uniqueConstraints": {},
@@ -639,10 +614,7 @@
"indexes": {
"model_workspace_model": {
"name": "model_workspace_model",
- "columns": [
- "workspace_id",
- "model"
- ],
+ "columns": ["workspace_id", "model"],
"isUnique": true
}
},
@@ -650,10 +622,7 @@
"compositePrimaryKeys": {
"model_workspace_id_id_pk": {
"name": "model_workspace_id_id_pk",
- "columns": [
- "workspace_id",
- "id"
- ]
+ "columns": ["workspace_id", "id"]
}
},
"uniqueConstraints": {},
@@ -717,10 +686,7 @@
"indexes": {
"workspace_provider": {
"name": "workspace_provider",
- "columns": [
- "workspace_id",
- "provider"
- ],
+ "columns": ["workspace_id", "provider"],
"isUnique": true
}
},
@@ -728,10 +694,7 @@
"compositePrimaryKeys": {
"provider_workspace_id_id_pk": {
"name": "provider_workspace_id_id_pk",
- "columns": [
- "workspace_id",
- "id"
- ]
+ "columns": ["workspace_id", "id"]
}
},
"uniqueConstraints": {},
@@ -844,32 +807,22 @@
"indexes": {
"user_account_id": {
"name": "user_account_id",
- "columns": [
- "workspace_id",
- "account_id"
- ],
+ "columns": ["workspace_id", "account_id"],
"isUnique": true
},
"user_email": {
"name": "user_email",
- "columns": [
- "workspace_id",
- "email"
- ],
+ "columns": ["workspace_id", "email"],
"isUnique": true
},
"global_account_id": {
"name": "global_account_id",
- "columns": [
- "account_id"
- ],
+ "columns": ["account_id"],
"isUnique": false
},
"global_email": {
"name": "global_email",
- "columns": [
- "email"
- ],
+ "columns": ["email"],
"isUnique": false
}
},
@@ -877,10 +830,7 @@
"compositePrimaryKeys": {
"user_workspace_id_id_pk": {
"name": "user_workspace_id_id_pk",
- "columns": [
- "workspace_id",
- "id"
- ]
+ "columns": ["workspace_id", "id"]
}
},
"uniqueConstraints": {},
@@ -937,9 +887,7 @@
"indexes": {
"slug": {
"name": "slug",
- "columns": [
- "slug"
- ],
+ "columns": ["slug"],
"isUnique": true
}
},
@@ -947,9 +895,7 @@
"compositePrimaryKeys": {
"workspace_id": {
"name": "workspace_id",
- "columns": [
- "id"
- ]
+ "columns": ["id"]
}
},
"uniqueConstraints": {},
@@ -966,4 +912,4 @@
"tables": {},
"indexes": {}
}
-}
\ No newline at end of file
+}
diff --git a/packages/console/core/migrations/meta/0037_snapshot.json b/packages/console/core/migrations/meta/0037_snapshot.json
index 690bae87..8a80ea52 100644
--- a/packages/console/core/migrations/meta/0037_snapshot.json
+++ b/packages/console/core/migrations/meta/0037_snapshot.json
@@ -43,9 +43,7 @@
"compositePrimaryKeys": {
"account_id_pk": {
"name": "account_id_pk",
- "columns": [
- "id"
- ]
+ "columns": ["id"]
}
},
"uniqueConstraints": {},
@@ -109,17 +107,12 @@
"indexes": {
"provider": {
"name": "provider",
- "columns": [
- "provider",
- "subject"
- ],
+ "columns": ["provider", "subject"],
"isUnique": true
},
"account_id": {
"name": "account_id",
- "columns": [
- "account_id"
- ],
+ "columns": ["account_id"],
"isUnique": false
}
},
@@ -127,9 +120,7 @@
"compositePrimaryKeys": {
"auth_id_pk": {
"name": "auth_id_pk",
- "columns": [
- "id"
- ]
+ "columns": ["id"]
}
},
"uniqueConstraints": {},
@@ -277,9 +268,7 @@
"indexes": {
"global_customer_id": {
"name": "global_customer_id",
- "columns": [
- "customer_id"
- ],
+ "columns": ["customer_id"],
"isUnique": true
}
},
@@ -287,10 +276,7 @@
"compositePrimaryKeys": {
"billing_workspace_id_id_pk": {
"name": "billing_workspace_id_id_pk",
- "columns": [
- "workspace_id",
- "id"
- ]
+ "columns": ["workspace_id", "id"]
}
},
"uniqueConstraints": {},
@@ -377,10 +363,7 @@
"compositePrimaryKeys": {
"payment_workspace_id_id_pk": {
"name": "payment_workspace_id_id_pk",
- "columns": [
- "workspace_id",
- "id"
- ]
+ "columns": ["workspace_id", "id"]
}
},
"uniqueConstraints": {},
@@ -502,10 +485,7 @@
"compositePrimaryKeys": {
"usage_workspace_id_id_pk": {
"name": "usage_workspace_id_id_pk",
- "columns": [
- "workspace_id",
- "id"
- ]
+ "columns": ["workspace_id", "id"]
}
},
"uniqueConstraints": {},
@@ -583,9 +563,7 @@
"indexes": {
"global_key": {
"name": "global_key",
- "columns": [
- "key"
- ],
+ "columns": ["key"],
"isUnique": true
}
},
@@ -593,10 +571,7 @@
"compositePrimaryKeys": {
"key_workspace_id_id_pk": {
"name": "key_workspace_id_id_pk",
- "columns": [
- "workspace_id",
- "id"
- ]
+ "columns": ["workspace_id", "id"]
}
},
"uniqueConstraints": {},
@@ -653,10 +628,7 @@
"indexes": {
"model_workspace_model": {
"name": "model_workspace_model",
- "columns": [
- "workspace_id",
- "model"
- ],
+ "columns": ["workspace_id", "model"],
"isUnique": true
}
},
@@ -664,10 +636,7 @@
"compositePrimaryKeys": {
"model_workspace_id_id_pk": {
"name": "model_workspace_id_id_pk",
- "columns": [
- "workspace_id",
- "id"
- ]
+ "columns": ["workspace_id", "id"]
}
},
"uniqueConstraints": {},
@@ -731,10 +700,7 @@
"indexes": {
"workspace_provider": {
"name": "workspace_provider",
- "columns": [
- "workspace_id",
- "provider"
- ],
+ "columns": ["workspace_id", "provider"],
"isUnique": true
}
},
@@ -742,10 +708,7 @@
"compositePrimaryKeys": {
"provider_workspace_id_id_pk": {
"name": "provider_workspace_id_id_pk",
- "columns": [
- "workspace_id",
- "id"
- ]
+ "columns": ["workspace_id", "id"]
}
},
"uniqueConstraints": {},
@@ -858,32 +821,22 @@
"indexes": {
"user_account_id": {
"name": "user_account_id",
- "columns": [
- "workspace_id",
- "account_id"
- ],
+ "columns": ["workspace_id", "account_id"],
"isUnique": true
},
"user_email": {
"name": "user_email",
- "columns": [
- "workspace_id",
- "email"
- ],
+ "columns": ["workspace_id", "email"],
"isUnique": true
},
"global_account_id": {
"name": "global_account_id",
- "columns": [
- "account_id"
- ],
+ "columns": ["account_id"],
"isUnique": false
},
"global_email": {
"name": "global_email",
- "columns": [
- "email"
- ],
+ "columns": ["email"],
"isUnique": false
}
},
@@ -891,10 +844,7 @@
"compositePrimaryKeys": {
"user_workspace_id_id_pk": {
"name": "user_workspace_id_id_pk",
- "columns": [
- "workspace_id",
- "id"
- ]
+ "columns": ["workspace_id", "id"]
}
},
"uniqueConstraints": {},
@@ -951,9 +901,7 @@
"indexes": {
"slug": {
"name": "slug",
- "columns": [
- "slug"
- ],
+ "columns": ["slug"],
"isUnique": true
}
},
@@ -961,9 +909,7 @@
"compositePrimaryKeys": {
"workspace_id": {
"name": "workspace_id",
- "columns": [
- "id"
- ]
+ "columns": ["id"]
}
},
"uniqueConstraints": {},
@@ -980,4 +926,4 @@
"tables": {},
"indexes": {}
}
-}
\ No newline at end of file
+}
diff --git a/packages/console/core/migrations/meta/_journal.json b/packages/console/core/migrations/meta/_journal.json
index f2c6c6fc..250fe59b 100644
--- a/packages/console/core/migrations/meta/_journal.json
+++ b/packages/console/core/migrations/meta/_journal.json
@@ -269,4 +269,4 @@
"breakpoints": true
}
]
-}
\ No newline at end of file
+}
diff --git a/packages/console/core/package.json b/packages/console/core/package.json
index c1ab2347..04421bbc 100644
--- a/packages/console/core/package.json
+++ b/packages/console/core/package.json
@@ -1,7 +1,7 @@
{
"$schema": "https://json.schemastore.org/package.json",
"name": "@opencode-ai/console-core",
- "version": "1.0.23",
+ "version": "1.0.55",
"private": true,
"type": "module",
"dependencies": {
diff --git a/packages/console/core/script/lookup-user.ts b/packages/console/core/script/lookup-user.ts
index af9bcc3a..1ae18c4d 100644
--- a/packages/console/core/script/lookup-user.ts
+++ b/packages/console/core/script/lookup-user.ts
@@ -8,22 +8,15 @@ if (!email) {
process.exit(1)
}
-const authData = await printTable("Auth", (tx) =>
- tx.select().from(AuthTable).where(eq(AuthTable.subject, email)),
-)
+const authData = await printTable("Auth", (tx) => tx.select().from(AuthTable).where(eq(AuthTable.subject, email)))
if (authData.length === 0) {
console.error("User not found")
process.exit(1)
}
-await printTable("Auth", (tx) =>
- tx.select().from(AuthTable).where(eq(AuthTable.accountID, authData[0].accountID)),
-)
+await printTable("Auth", (tx) => tx.select().from(AuthTable).where(eq(AuthTable.accountID, authData[0].accountID)))
-function printTable(
- title: string,
- callback: (tx: Database.TxOrDb) => Promise,
-): Promise {
+function printTable(title: string, callback: (tx: Database.TxOrDb) => Promise): Promise {
return Database.use(async (tx) => {
const data = await callback(tx)
console.log(`== ${title} ==`)
diff --git a/packages/console/core/script/reset-db.ts b/packages/console/core/script/reset-db.ts
index bd00e196..02d49890 100644
--- a/packages/console/core/script/reset-db.ts
+++ b/packages/console/core/script/reset-db.ts
@@ -8,14 +8,6 @@ import { KeyTable } from "../src/schema/key.sql.js"
if (Resource.App.stage !== "frank") throw new Error("This script is only for frank")
-for (const table of [
- AccountTable,
- BillingTable,
- KeyTable,
- PaymentTable,
- UsageTable,
- UserTable,
- WorkspaceTable,
-]) {
+for (const table of [AccountTable, BillingTable, KeyTable, PaymentTable, UsageTable, UserTable, WorkspaceTable]) {
await Database.use((tx) => tx.delete(table))
}
diff --git a/packages/console/core/script/update-models.ts b/packages/console/core/script/update-models.ts
index e7a24551..807d5782 100755
--- a/packages/console/core/script/update-models.ts
+++ b/packages/console/core/script/update-models.ts
@@ -7,7 +7,6 @@ import { ZenData } from "../src/model"
const root = path.resolve(process.cwd(), "..", "..", "..")
const models = await $`bun sst secret list`.cwd(root).text()
-console.log("models", models)
// read the line starting with "ZEN_MODELS"
const oldValue1 = models
diff --git a/packages/console/core/src/billing.ts b/packages/console/core/src/billing.ts
index 70bf1bc3..34871814 100644
--- a/packages/console/core/src/billing.ts
+++ b/packages/console/core/src/billing.ts
@@ -10,13 +10,12 @@ import { centsToMicroCents } from "./util/price"
import { User } from "./user"
export namespace Billing {
- export const CHARGE_NAME = "opencode credits"
- export const CHARGE_FEE_NAME = "processing fee"
- export const CHARGE_AMOUNT = 2000 // $20
- export const CHARGE_AMOUNT_DOLLAR = 20
- export const CHARGE_FEE = 123 // Stripe fee 4.4% + $0.30
- export const CHARGE_THRESHOLD_DOLLAR = 5
- export const CHARGE_THRESHOLD = 500 // $5
+ export const ITEM_CREDIT_NAME = "opencode credits"
+ export const ITEM_FEE_NAME = "processing fee"
+ export const RELOAD_AMOUNT = 20
+ export const RELOAD_AMOUNT_MIN = 10
+ export const RELOAD_TRIGGER = 5
+ export const RELOAD_TRIGGER_MIN = 5
export const stripe = () =>
new Stripe(Resource.STRIPE_SECRET_KEY.value, {
apiVersion: "2025-03-31.basil",
@@ -33,6 +32,8 @@ export namespace Billing {
paymentMethodLast4: BillingTable.paymentMethodLast4,
balance: BillingTable.balance,
reload: BillingTable.reload,
+ reloadAmount: BillingTable.reloadAmount,
+ reloadTrigger: BillingTable.reloadTrigger,
monthlyLimit: BillingTable.monthlyLimit,
monthlyUsage: BillingTable.monthlyUsage,
timeMonthlyUsageUpdated: BillingTable.timeMonthlyUsageUpdated,
@@ -67,17 +68,28 @@ export namespace Billing {
)
}
+ export const calculateFeeInCents = (x: number) => {
+ // math: x = total - (total * 0.044 + 0.30)
+ // math: x = total * (1-0.044) - 0.30
+ // math: (x + 0.30) / 0.956 = total
+ return Math.round(((x + 30) / 0.956) * 0.044 + 30)
+ }
+
export const reload = async () => {
- const { customerID, paymentMethodID } = await Database.use((tx) =>
+ const billing = await Database.use((tx) =>
tx
.select({
customerID: BillingTable.customerID,
paymentMethodID: BillingTable.paymentMethodID,
+ reloadAmount: BillingTable.reloadAmount,
})
.from(BillingTable)
.where(eq(BillingTable.workspaceID, Actor.workspace()))
.then((rows) => rows[0]),
)
+ const customerID = billing.customerID
+ const paymentMethodID = billing.paymentMethodID
+ const amountInCents = (billing.reloadAmount ?? Billing.RELOAD_AMOUNT) * 100
const paymentID = Identifier.create("payment")
let invoice
try {
@@ -89,18 +101,18 @@ export namespace Billing {
currency: "usd",
})
await Billing.stripe().invoiceItems.create({
- amount: Billing.CHARGE_AMOUNT,
+ amount: amountInCents,
currency: "usd",
customer: customerID!,
- description: CHARGE_NAME,
invoice: draft.id!,
+ description: ITEM_CREDIT_NAME,
})
await Billing.stripe().invoiceItems.create({
- amount: Billing.CHARGE_FEE,
+ amount: calculateFeeInCents(amountInCents),
currency: "usd",
customer: customerID!,
- description: CHARGE_FEE_NAME,
invoice: draft.id!,
+ description: ITEM_FEE_NAME,
})
await Billing.stripe().invoices.finalizeInvoice(draft.id!)
invoice = await Billing.stripe().invoices.pay(draft.id!, {
@@ -128,7 +140,7 @@ export namespace Billing {
await tx
.update(BillingTable)
.set({
- balance: sql`${BillingTable.balance} + ${centsToMicroCents(CHARGE_AMOUNT)}`,
+ balance: sql`${BillingTable.balance} + ${centsToMicroCents(amountInCents)}`,
reloadError: null,
timeReloadError: null,
})
@@ -136,7 +148,7 @@ export namespace Billing {
await tx.insert(PaymentTable).values({
workspaceID: Actor.workspace(),
id: paymentID,
- amount: centsToMicroCents(CHARGE_AMOUNT),
+ amount: centsToMicroCents(amountInCents),
invoiceID: invoice.id!,
paymentID: invoice.payments?.data[0].payment.payment_intent as string,
customerID,
@@ -159,13 +171,19 @@ export namespace Billing {
z.object({
successUrl: z.string(),
cancelUrl: z.string(),
+ amount: z.number().optional(),
}),
async (input) => {
const user = Actor.assert("user")
- const { successUrl, cancelUrl } = input
+ const { successUrl, cancelUrl, amount } = input
+
+ if (amount !== undefined && amount < Billing.RELOAD_AMOUNT_MIN) {
+ throw new Error(`Amount must be at least $${Billing.RELOAD_AMOUNT_MIN}`)
+ }
const email = await User.getAuthEmail(user.properties.userID)
const customer = await Billing.get()
+ const amountInCents = (amount ?? customer.reloadAmount ?? Billing.RELOAD_AMOUNT) * 100
const session = await Billing.stripe().checkout.sessions.create({
mode: "payment",
billing_address_collection: "required",
@@ -173,20 +191,16 @@ export namespace Billing {
{
price_data: {
currency: "usd",
- product_data: {
- name: CHARGE_NAME,
- },
- unit_amount: CHARGE_AMOUNT,
+ product_data: { name: ITEM_CREDIT_NAME },
+ unit_amount: amountInCents,
},
quantity: 1,
},
{
price_data: {
currency: "usd",
- product_data: {
- name: CHARGE_FEE_NAME,
- },
- unit_amount: CHARGE_FEE,
+ product_data: { name: ITEM_FEE_NAME },
+ unit_amount: calculateFeeInCents(amountInCents),
},
quantity: 1,
},
@@ -218,6 +232,7 @@ export namespace Billing {
},
metadata: {
workspaceID: Actor.workspace(),
+ amount: amountInCents.toString(),
},
success_url: successUrl,
cancel_url: cancelUrl,
diff --git a/packages/console/core/src/model.ts b/packages/console/core/src/model.ts
index 30cc15e4..46b2aa55 100644
--- a/packages/console/core/src/model.ts
+++ b/packages/console/core/src/model.ts
@@ -24,6 +24,7 @@ export namespace ZenData {
cost: ModelCostSchema,
cost200K: ModelCostSchema.optional(),
allowAnonymous: z.boolean().optional(),
+ rateLimit: z.number().optional(),
providers: z.array(
z.object({
id: z.string(),
@@ -60,9 +61,7 @@ export namespace Model {
export const enable = fn(z.object({ model: z.string() }), ({ model }) => {
Actor.assertAdmin()
return Database.use((db) =>
- db
- .delete(ModelTable)
- .where(and(eq(ModelTable.workspaceID, Actor.workspace()), eq(ModelTable.model, model))),
+ db.delete(ModelTable).where(and(eq(ModelTable.workspaceID, Actor.workspace()), eq(ModelTable.model, model))),
)
})
diff --git a/packages/console/core/sst-env.d.ts b/packages/console/core/sst-env.d.ts
index 01407434..bcd7c265 100644
--- a/packages/console/core/sst-env.d.ts
+++ b/packages/console/core/sst-env.d.ts
@@ -6,99 +6,108 @@
import "sst"
declare module "sst" {
export interface Resource {
- "ADMIN_SECRET": {
- "type": "sst.sst.Secret"
- "value": string
+ ADMIN_SECRET: {
+ type: "sst.sst.Secret"
+ value: string
}
- "AUTH_API_URL": {
- "type": "sst.sst.Linkable"
- "value": string
+ AUTH_API_URL: {
+ type: "sst.sst.Linkable"
+ value: string
}
- "AWS_SES_ACCESS_KEY_ID": {
- "type": "sst.sst.Secret"
- "value": string
+ AWS_SES_ACCESS_KEY_ID: {
+ type: "sst.sst.Secret"
+ value: string
}
- "AWS_SES_SECRET_ACCESS_KEY": {
- "type": "sst.sst.Secret"
- "value": string
+ AWS_SES_SECRET_ACCESS_KEY: {
+ type: "sst.sst.Secret"
+ value: string
}
- "Console": {
- "type": "sst.cloudflare.SolidStart"
- "url": string
+ CLOUDFLARE_API_TOKEN: {
+ type: "sst.sst.Secret"
+ value: string
}
- "Database": {
- "database": string
- "host": string
- "password": string
- "port": number
- "type": "sst.sst.Linkable"
- "username": string
+ CLOUDFLARE_DEFAULT_ACCOUNT_ID: {
+ type: "sst.sst.Secret"
+ value: string
}
- "Desktop": {
- "type": "sst.cloudflare.StaticSite"
- "url": string
+ Console: {
+ type: "sst.cloudflare.SolidStart"
+ url: string
}
- "EMAILOCTOPUS_API_KEY": {
- "type": "sst.sst.Secret"
- "value": string
+ Database: {
+ database: string
+ host: string
+ password: string
+ port: number
+ type: "sst.sst.Linkable"
+ username: string
}
- "GITHUB_APP_ID": {
- "type": "sst.sst.Secret"
- "value": string
+ Desktop: {
+ type: "sst.cloudflare.StaticSite"
+ url: string
}
- "GITHUB_APP_PRIVATE_KEY": {
- "type": "sst.sst.Secret"
- "value": string
+ EMAILOCTOPUS_API_KEY: {
+ type: "sst.sst.Secret"
+ value: string
}
- "GITHUB_CLIENT_ID_CONSOLE": {
- "type": "sst.sst.Secret"
- "value": string
+ GITHUB_APP_ID: {
+ type: "sst.sst.Secret"
+ value: string
}
- "GITHUB_CLIENT_SECRET_CONSOLE": {
- "type": "sst.sst.Secret"
- "value": string
+ GITHUB_APP_PRIVATE_KEY: {
+ type: "sst.sst.Secret"
+ value: string
}
- "GOOGLE_CLIENT_ID": {
- "type": "sst.sst.Secret"
- "value": string
+ GITHUB_CLIENT_ID_CONSOLE: {
+ type: "sst.sst.Secret"
+ value: string
}
- "HONEYCOMB_API_KEY": {
- "type": "sst.sst.Secret"
- "value": string
+ GITHUB_CLIENT_SECRET_CONSOLE: {
+ type: "sst.sst.Secret"
+ value: string
}
- "STRIPE_SECRET_KEY": {
- "type": "sst.sst.Secret"
- "value": string
+ GOOGLE_CLIENT_ID: {
+ type: "sst.sst.Secret"
+ value: string
}
- "STRIPE_WEBHOOK_SECRET": {
- "type": "sst.sst.Linkable"
- "value": string
+ HONEYCOMB_API_KEY: {
+ type: "sst.sst.Secret"
+ value: string
}
- "Web": {
- "type": "sst.cloudflare.Astro"
- "url": string
+ STRIPE_SECRET_KEY: {
+ type: "sst.sst.Secret"
+ value: string
}
- "ZEN_MODELS1": {
- "type": "sst.sst.Secret"
- "value": string
+ STRIPE_WEBHOOK_SECRET: {
+ type: "sst.sst.Linkable"
+ value: string
}
- "ZEN_MODELS2": {
- "type": "sst.sst.Secret"
- "value": string
+ Web: {
+ type: "sst.cloudflare.Astro"
+ url: string
+ }
+ ZEN_MODELS1: {
+ type: "sst.sst.Secret"
+ value: string
+ }
+ ZEN_MODELS2: {
+ type: "sst.sst.Secret"
+ value: string
}
}
}
-// cloudflare
-import * as cloudflare from "@cloudflare/workers-types";
+// cloudflare
+import * as cloudflare from "@cloudflare/workers-types"
declare module "sst" {
export interface Resource {
- "Api": cloudflare.Service
- "AuthApi": cloudflare.Service
- "AuthStorage": cloudflare.KVNamespace
- "Bucket": cloudflare.R2Bucket
- "LogProcessor": cloudflare.Service
+ Api: cloudflare.Service
+ AuthApi: cloudflare.Service
+ AuthStorage: cloudflare.KVNamespace
+ Bucket: cloudflare.R2Bucket
+ GatewayKv: cloudflare.KVNamespace
+ LogProcessor: cloudflare.Service
}
}
import "sst"
-export {}
\ No newline at end of file
+export {}
diff --git a/packages/console/function/package.json b/packages/console/function/package.json
index 0c6e0288..26af4c7c 100644
--- a/packages/console/function/package.json
+++ b/packages/console/function/package.json
@@ -1,6 +1,6 @@
{
"name": "@opencode-ai/console-function",
- "version": "1.0.23",
+ "version": "1.0.55",
"$schema": "https://json.schemastore.org/package.json",
"private": true,
"type": "module",
diff --git a/packages/console/function/sst-env.d.ts b/packages/console/function/sst-env.d.ts
index 01407434..bcd7c265 100644
--- a/packages/console/function/sst-env.d.ts
+++ b/packages/console/function/sst-env.d.ts
@@ -6,99 +6,108 @@
import "sst"
declare module "sst" {
export interface Resource {
- "ADMIN_SECRET": {
- "type": "sst.sst.Secret"
- "value": string
+ ADMIN_SECRET: {
+ type: "sst.sst.Secret"
+ value: string
}
- "AUTH_API_URL": {
- "type": "sst.sst.Linkable"
- "value": string
+ AUTH_API_URL: {
+ type: "sst.sst.Linkable"
+ value: string
}
- "AWS_SES_ACCESS_KEY_ID": {
- "type": "sst.sst.Secret"
- "value": string
+ AWS_SES_ACCESS_KEY_ID: {
+ type: "sst.sst.Secret"
+ value: string
}
- "AWS_SES_SECRET_ACCESS_KEY": {
- "type": "sst.sst.Secret"
- "value": string
+ AWS_SES_SECRET_ACCESS_KEY: {
+ type: "sst.sst.Secret"
+ value: string
}
- "Console": {
- "type": "sst.cloudflare.SolidStart"
- "url": string
+ CLOUDFLARE_API_TOKEN: {
+ type: "sst.sst.Secret"
+ value: string
}
- "Database": {
- "database": string
- "host": string
- "password": string
- "port": number
- "type": "sst.sst.Linkable"
- "username": string
+ CLOUDFLARE_DEFAULT_ACCOUNT_ID: {
+ type: "sst.sst.Secret"
+ value: string
}
- "Desktop": {
- "type": "sst.cloudflare.StaticSite"
- "url": string
+ Console: {
+ type: "sst.cloudflare.SolidStart"
+ url: string
}
- "EMAILOCTOPUS_API_KEY": {
- "type": "sst.sst.Secret"
- "value": string
+ Database: {
+ database: string
+ host: string
+ password: string
+ port: number
+ type: "sst.sst.Linkable"
+ username: string
}
- "GITHUB_APP_ID": {
- "type": "sst.sst.Secret"
- "value": string
+ Desktop: {
+ type: "sst.cloudflare.StaticSite"
+ url: string
}
- "GITHUB_APP_PRIVATE_KEY": {
- "type": "sst.sst.Secret"
- "value": string
+ EMAILOCTOPUS_API_KEY: {
+ type: "sst.sst.Secret"
+ value: string
}
- "GITHUB_CLIENT_ID_CONSOLE": {
- "type": "sst.sst.Secret"
- "value": string
+ GITHUB_APP_ID: {
+ type: "sst.sst.Secret"
+ value: string
}
- "GITHUB_CLIENT_SECRET_CONSOLE": {
- "type": "sst.sst.Secret"
- "value": string
+ GITHUB_APP_PRIVATE_KEY: {
+ type: "sst.sst.Secret"
+ value: string
}
- "GOOGLE_CLIENT_ID": {
- "type": "sst.sst.Secret"
- "value": string
+ GITHUB_CLIENT_ID_CONSOLE: {
+ type: "sst.sst.Secret"
+ value: string
}
- "HONEYCOMB_API_KEY": {
- "type": "sst.sst.Secret"
- "value": string
+ GITHUB_CLIENT_SECRET_CONSOLE: {
+ type: "sst.sst.Secret"
+ value: string
}
- "STRIPE_SECRET_KEY": {
- "type": "sst.sst.Secret"
- "value": string
+ GOOGLE_CLIENT_ID: {
+ type: "sst.sst.Secret"
+ value: string
}
- "STRIPE_WEBHOOK_SECRET": {
- "type": "sst.sst.Linkable"
- "value": string
+ HONEYCOMB_API_KEY: {
+ type: "sst.sst.Secret"
+ value: string
}
- "Web": {
- "type": "sst.cloudflare.Astro"
- "url": string
+ STRIPE_SECRET_KEY: {
+ type: "sst.sst.Secret"
+ value: string
}
- "ZEN_MODELS1": {
- "type": "sst.sst.Secret"
- "value": string
+ STRIPE_WEBHOOK_SECRET: {
+ type: "sst.sst.Linkable"
+ value: string
}
- "ZEN_MODELS2": {
- "type": "sst.sst.Secret"
- "value": string
+ Web: {
+ type: "sst.cloudflare.Astro"
+ url: string
+ }
+ ZEN_MODELS1: {
+ type: "sst.sst.Secret"
+ value: string
+ }
+ ZEN_MODELS2: {
+ type: "sst.sst.Secret"
+ value: string
}
}
}
-// cloudflare
-import * as cloudflare from "@cloudflare/workers-types";
+// cloudflare
+import * as cloudflare from "@cloudflare/workers-types"
declare module "sst" {
export interface Resource {
- "Api": cloudflare.Service
- "AuthApi": cloudflare.Service
- "AuthStorage": cloudflare.KVNamespace
- "Bucket": cloudflare.R2Bucket
- "LogProcessor": cloudflare.Service
+ Api: cloudflare.Service
+ AuthApi: cloudflare.Service
+ AuthStorage: cloudflare.KVNamespace
+ Bucket: cloudflare.R2Bucket
+ GatewayKv: cloudflare.KVNamespace
+ LogProcessor: cloudflare.Service
}
}
import "sst"
-export {}
\ No newline at end of file
+export {}
diff --git a/packages/console/mail/package.json b/packages/console/mail/package.json
index 30e772b6..ef70beb6 100644
--- a/packages/console/mail/package.json
+++ b/packages/console/mail/package.json
@@ -1,6 +1,6 @@
{
"name": "@opencode-ai/console-mail",
- "version": "1.0.23",
+ "version": "1.0.55",
"dependencies": {
"@jsx-email/all": "2.2.3",
"@jsx-email/cli": "1.4.3",
diff --git a/packages/console/mail/sst-env.d.ts b/packages/console/mail/sst-env.d.ts
index 9b9de732..bd558821 100644
--- a/packages/console/mail/sst-env.d.ts
+++ b/packages/console/mail/sst-env.d.ts
@@ -6,4 +6,4 @@
///
import "sst"
-export {}
\ No newline at end of file
+export {}
diff --git a/packages/console/resource/package.json b/packages/console/resource/package.json
index 6553feed..f110f6c2 100644
--- a/packages/console/resource/package.json
+++ b/packages/console/resource/package.json
@@ -13,6 +13,9 @@
}
},
"devDependencies": {
- "@tsconfig/node22": "22.0.2"
+ "@cloudflare/workers-types": "catalog:",
+ "@tsconfig/node22": "22.0.2",
+ "@types/node": "catalog:",
+ "cloudflare": "5.2.0"
}
}
diff --git a/packages/console/resource/resource.node.ts b/packages/console/resource/resource.node.ts
index d7dbb6c6..f63d7bad 100644
--- a/packages/console/resource/resource.node.ts
+++ b/packages/console/resource/resource.node.ts
@@ -1 +1,58 @@
-export { Resource } from "sst"
+import type { KVNamespaceListOptions, KVNamespaceListResult, KVNamespacePutOptions } from "@cloudflare/workers-types"
+import { Resource as ResourceBase } from "sst"
+import Cloudflare from "cloudflare"
+
+export const Resource = new Proxy(
+ {},
+ {
+ get(_target, prop: keyof typeof ResourceBase) {
+ const value = ResourceBase[prop]
+ // @ts-ignore
+ if ("type" in value && value.type === "sst.cloudflare.Kv") {
+ const client = new Cloudflare({
+ apiToken: ResourceBase.CLOUDFLARE_API_TOKEN.value,
+ })
+ // @ts-ignore
+ const namespaceId = value.namespaceId
+ const accountId = ResourceBase.CLOUDFLARE_DEFAULT_ACCOUNT_ID.value
+ return {
+ get: (k: string | string[]) => {
+ const isMulti = Array.isArray(k)
+ return client.kv.namespaces
+ .bulkGet(namespaceId, {
+ keys: Array.isArray(k) ? k : [k],
+ account_id: accountId,
+ })
+ .then((result) => (isMulti ? new Map(Object.entries(result?.values ?? {})) : result?.values?.[k]))
+ },
+ put: (k: string, v: string, opts?: KVNamespacePutOptions) =>
+ client.kv.namespaces.values.update(namespaceId, k, {
+ account_id: accountId,
+ value: v,
+ expiration: opts?.expiration,
+ expiration_ttl: opts?.expirationTtl,
+ metadata: opts?.metadata,
+ }),
+ delete: (k: string) =>
+ client.kv.namespaces.values.delete(namespaceId, k, {
+ account_id: accountId,
+ }),
+ list: (opts?: KVNamespaceListOptions): Promise> =>
+ client.kv.namespaces.keys
+ .list(namespaceId, {
+ account_id: accountId,
+ prefix: opts?.prefix ?? undefined,
+ })
+ .then((result) => {
+ return {
+ keys: result.result,
+ list_complete: true,
+ cacheStatus: null,
+ }
+ }),
+ }
+ }
+ return value
+ },
+ },
+) as Record
diff --git a/packages/console/resource/sst-env.d.ts b/packages/console/resource/sst-env.d.ts
index 01407434..bcd7c265 100644
--- a/packages/console/resource/sst-env.d.ts
+++ b/packages/console/resource/sst-env.d.ts
@@ -6,99 +6,108 @@
import "sst"
declare module "sst" {
export interface Resource {
- "ADMIN_SECRET": {
- "type": "sst.sst.Secret"
- "value": string
+ ADMIN_SECRET: {
+ type: "sst.sst.Secret"
+ value: string
}
- "AUTH_API_URL": {
- "type": "sst.sst.Linkable"
- "value": string
+ AUTH_API_URL: {
+ type: "sst.sst.Linkable"
+ value: string
}
- "AWS_SES_ACCESS_KEY_ID": {
- "type": "sst.sst.Secret"
- "value": string
+ AWS_SES_ACCESS_KEY_ID: {
+ type: "sst.sst.Secret"
+ value: string
}
- "AWS_SES_SECRET_ACCESS_KEY": {
- "type": "sst.sst.Secret"
- "value": string
+ AWS_SES_SECRET_ACCESS_KEY: {
+ type: "sst.sst.Secret"
+ value: string
}
- "Console": {
- "type": "sst.cloudflare.SolidStart"
- "url": string
+ CLOUDFLARE_API_TOKEN: {
+ type: "sst.sst.Secret"
+ value: string
}
- "Database": {
- "database": string
- "host": string
- "password": string
- "port": number
- "type": "sst.sst.Linkable"
- "username": string
+ CLOUDFLARE_DEFAULT_ACCOUNT_ID: {
+ type: "sst.sst.Secret"
+ value: string
}
- "Desktop": {
- "type": "sst.cloudflare.StaticSite"
- "url": string
+ Console: {
+ type: "sst.cloudflare.SolidStart"
+ url: string
}
- "EMAILOCTOPUS_API_KEY": {
- "type": "sst.sst.Secret"
- "value": string
+ Database: {
+ database: string
+ host: string
+ password: string
+ port: number
+ type: "sst.sst.Linkable"
+ username: string
}
- "GITHUB_APP_ID": {
- "type": "sst.sst.Secret"
- "value": string
+ Desktop: {
+ type: "sst.cloudflare.StaticSite"
+ url: string
}
- "GITHUB_APP_PRIVATE_KEY": {
- "type": "sst.sst.Secret"
- "value": string
+ EMAILOCTOPUS_API_KEY: {
+ type: "sst.sst.Secret"
+ value: string
}
- "GITHUB_CLIENT_ID_CONSOLE": {
- "type": "sst.sst.Secret"
- "value": string
+ GITHUB_APP_ID: {
+ type: "sst.sst.Secret"
+ value: string
}
- "GITHUB_CLIENT_SECRET_CONSOLE": {
- "type": "sst.sst.Secret"
- "value": string
+ GITHUB_APP_PRIVATE_KEY: {
+ type: "sst.sst.Secret"
+ value: string
}
- "GOOGLE_CLIENT_ID": {
- "type": "sst.sst.Secret"
- "value": string
+ GITHUB_CLIENT_ID_CONSOLE: {
+ type: "sst.sst.Secret"
+ value: string
}
- "HONEYCOMB_API_KEY": {
- "type": "sst.sst.Secret"
- "value": string
+ GITHUB_CLIENT_SECRET_CONSOLE: {
+ type: "sst.sst.Secret"
+ value: string
}
- "STRIPE_SECRET_KEY": {
- "type": "sst.sst.Secret"
- "value": string
+ GOOGLE_CLIENT_ID: {
+ type: "sst.sst.Secret"
+ value: string
}
- "STRIPE_WEBHOOK_SECRET": {
- "type": "sst.sst.Linkable"
- "value": string
+ HONEYCOMB_API_KEY: {
+ type: "sst.sst.Secret"
+ value: string
}
- "Web": {
- "type": "sst.cloudflare.Astro"
- "url": string
+ STRIPE_SECRET_KEY: {
+ type: "sst.sst.Secret"
+ value: string
}
- "ZEN_MODELS1": {
- "type": "sst.sst.Secret"
- "value": string
+ STRIPE_WEBHOOK_SECRET: {
+ type: "sst.sst.Linkable"
+ value: string
}
- "ZEN_MODELS2": {
- "type": "sst.sst.Secret"
- "value": string
+ Web: {
+ type: "sst.cloudflare.Astro"
+ url: string
+ }
+ ZEN_MODELS1: {
+ type: "sst.sst.Secret"
+ value: string
+ }
+ ZEN_MODELS2: {
+ type: "sst.sst.Secret"
+ value: string
}
}
}
-// cloudflare
-import * as cloudflare from "@cloudflare/workers-types";
+// cloudflare
+import * as cloudflare from "@cloudflare/workers-types"
declare module "sst" {
export interface Resource {
- "Api": cloudflare.Service
- "AuthApi": cloudflare.Service
- "AuthStorage": cloudflare.KVNamespace
- "Bucket": cloudflare.R2Bucket
- "LogProcessor": cloudflare.Service
+ Api: cloudflare.Service
+ AuthApi: cloudflare.Service
+ AuthStorage: cloudflare.KVNamespace
+ Bucket: cloudflare.R2Bucket
+ GatewayKv: cloudflare.KVNamespace
+ LogProcessor: cloudflare.Service
}
}
import "sst"
-export {}
\ No newline at end of file
+export {}
diff --git a/packages/desktop/package.json b/packages/desktop/package.json
index 34188445..25b278c4 100644
--- a/packages/desktop/package.json
+++ b/packages/desktop/package.json
@@ -1,6 +1,6 @@
{
"name": "@opencode-ai/desktop",
- "version": "1.0.23",
+ "version": "1.0.55",
"description": "",
"type": "module",
"scripts": {
@@ -31,6 +31,7 @@
"@solid-primitives/event-bus": "1.1.2",
"@solid-primitives/resize-observer": "2.1.3",
"@solid-primitives/scroll": "2.1.3",
+ "@solid-primitives/storage": "4.3.3",
"@solidjs/meta": "catalog:",
"@solidjs/router": "0.15.3",
"@thisbeyond/solid-dnd": "0.7.5",
@@ -45,9 +46,5 @@
"solid-list": "catalog:",
"tailwindcss": "catalog:",
"virtua": "catalog:"
- },
- "prettier": {
- "semi": false,
- "printWidth": 120
}
}
diff --git a/packages/desktop/src/components/code.tsx b/packages/desktop/src/components/code.tsx
deleted file mode 100644
index 325f7b63..00000000
--- a/packages/desktop/src/components/code.tsx
+++ /dev/null
@@ -1,846 +0,0 @@
-import { bundledLanguages, type BundledLanguage, type ShikiTransformer } from "shiki"
-import { splitProps, type ComponentProps, createEffect, onMount, onCleanup, createMemo, createResource } from "solid-js"
-import { useLocal, type TextSelection } from "@/context/local"
-import { getFileExtension, getNodeOffsetInLine, getSelectionInContainer } from "@/utils"
-import { useShiki } from "@opencode-ai/ui"
-
-type DefinedSelection = Exclude
-
-interface Props extends ComponentProps<"div"> {
- code: string
- path: string
-}
-
-export function Code(props: Props) {
- const ctx = useLocal()
- const highlighter = useShiki()
- const [local, others] = splitProps(props, ["class", "classList", "code", "path"])
- const lang = createMemo(() => {
- const ext = getFileExtension(local.path)
- if (ext in bundledLanguages) return ext
- return "text"
- })
-
- let container: HTMLDivElement | undefined
- let isProgrammaticSelection = false
-
- const ranges = createMemo(() => {
- const items = ctx.context.all() as Array<{ type: "file"; path: string; selection?: DefinedSelection }>
- const result: DefinedSelection[] = []
- for (const item of items) {
- if (item.path !== local.path) continue
- const selection = item.selection
- if (!selection) continue
- result.push(selection)
- }
- return result
- })
-
- const createLineNumberTransformer = (selections: DefinedSelection[]): ShikiTransformer => {
- const highlighted = new Set()
- for (const selection of selections) {
- const startLine = selection.startLine
- const endLine = selection.endLine
- const start = Math.max(1, Math.min(startLine, endLine))
- const end = Math.max(start, Math.max(startLine, endLine))
- const count = end - start + 1
- if (count <= 0) continue
- const values = Array.from({ length: count }, (_, index) => start + index)
- for (const value of values) highlighted.add(value)
- }
- return {
- name: "line-number-highlight",
- line(node, index) {
- if (!highlighted.has(index)) return
- this.addClassToHast(node, "line-number-highlight")
- const children = node.children
- if (!Array.isArray(children)) return
- for (const child of children) {
- if (!child || typeof child !== "object") continue
- const element = child as { type?: string; properties?: { className?: string[] } }
- if (element.type !== "element") continue
- const className = element.properties?.className
- if (!Array.isArray(className)) continue
- const matches = className.includes("diff-oldln") || className.includes("diff-newln")
- if (!matches) continue
- if (className.includes("line-number-highlight")) continue
- className.push("line-number-highlight")
- }
- },
- }
- }
-
- const [html] = createResource(
- () => ranges(),
- async (activeRanges) => {
- if (!highlighter.getLoadedLanguages().includes(lang())) {
- await highlighter.loadLanguage(lang() as BundledLanguage)
- }
- return highlighter.codeToHtml(local.code || "", {
- lang: lang() && lang() in bundledLanguages ? lang() : "text",
- theme: "opencode",
- transformers: [transformerUnifiedDiff(), transformerDiffGroups(), createLineNumberTransformer(activeRanges)],
- }) as string
- },
- )
-
- onMount(() => {
- if (!container) return
-
- let ticking = false
- const onScroll = () => {
- if (!container) return
- // if (ctx.file.active()?.path !== local.path) return
- if (ticking) return
- ticking = true
- requestAnimationFrame(() => {
- ticking = false
- ctx.file.scroll(local.path, container!.scrollTop)
- })
- }
-
- const onSelectionChange = () => {
- if (!container) return
- if (isProgrammaticSelection) return
- // if (ctx.file.active()?.path !== local.path) return
- const d = getSelectionInContainer(container)
- if (!d) return
- const p = ctx.file.node(local.path)?.selection
- if (p && p.startLine === d.sl && p.endLine === d.el && p.startChar === d.sch && p.endChar === d.ech) return
- ctx.file.select(local.path, { startLine: d.sl, startChar: d.sch, endLine: d.el, endChar: d.ech })
- }
-
- const MOD = typeof navigator === "object" && /(Mac|iPod|iPhone|iPad)/.test(navigator.platform) ? "Meta" : "Control"
- const onKeyDown = (e: KeyboardEvent) => {
- // if (ctx.file.active()?.path !== local.path) return
- const ae = document.activeElement as HTMLElement | undefined
- const tag = (ae?.tagName || "").toLowerCase()
- const inputFocused = !!ae && (tag === "input" || tag === "textarea" || ae.isContentEditable)
- if (inputFocused) return
- if (e.getModifierState(MOD) && e.key.toLowerCase() === "a") {
- e.preventDefault()
- if (!container) return
- const element = container.querySelector("code") as HTMLElement | undefined
- if (!element) return
- const lines = Array.from(element.querySelectorAll(".line"))
- if (!lines.length) return
- const r = document.createRange()
- const last = lines[lines.length - 1]
- r.selectNodeContents(last)
- const lastLen = r.toString().length
- ctx.file.select(local.path, { startLine: 1, startChar: 0, endLine: lines.length, endChar: lastLen })
- }
- }
-
- container.addEventListener("scroll", onScroll)
- document.addEventListener("selectionchange", onSelectionChange)
- document.addEventListener("keydown", onKeyDown)
-
- onCleanup(() => {
- container?.removeEventListener("scroll", onScroll)
- document.removeEventListener("selectionchange", onSelectionChange)
- document.removeEventListener("keydown", onKeyDown)
- })
- })
-
- // Restore scroll position from store when content is ready
- createEffect(() => {
- const content = html()
- if (!container || !content) return
- const top = ctx.file.node(local.path)?.scrollTop
- if (top !== undefined && container.scrollTop !== top) container.scrollTop = top
- })
-
- // Sync selection from store -> DOM
- createEffect(() => {
- const content = html()
- if (!container || !content) return
- // if (ctx.file.active()?.path !== local.path) return
- const codeEl = container.querySelector("code") as HTMLElement | undefined
- if (!codeEl) return
- const target = ctx.file.node(local.path)?.selection
- const current = getSelectionInContainer(container)
- const sel = window.getSelection()
- if (!sel) return
- if (!target) {
- if (current) {
- isProgrammaticSelection = true
- sel.removeAllRanges()
- queueMicrotask(() => {
- isProgrammaticSelection = false
- })
- }
- return
- }
- const matches = !!(
- current &&
- current.sl === target.startLine &&
- current.sch === target.startChar &&
- current.el === target.endLine &&
- current.ech === target.endChar
- )
- if (matches) return
- const lines = Array.from(codeEl.querySelectorAll(".line"))
- if (lines.length === 0) return
- let sIdx = Math.max(0, target.startLine - 1)
- let eIdx = Math.max(0, target.endLine - 1)
- let sChar = Math.max(0, target.startChar || 0)
- let eChar = Math.max(0, target.endChar || 0)
- if (sIdx > eIdx || (sIdx === eIdx && sChar > eChar)) {
- const ti = sIdx
- sIdx = eIdx
- eIdx = ti
- const tc = sChar
- sChar = eChar
- eChar = tc
- }
- if (eChar === 0 && eIdx > sIdx) {
- eIdx = eIdx - 1
- eChar = Number.POSITIVE_INFINITY
- }
- if (sIdx >= lines.length) return
- if (eIdx >= lines.length) eIdx = lines.length - 1
- const s = getNodeOffsetInLine(lines[sIdx], sChar) ?? { node: lines[sIdx], offset: 0 }
- const e = getNodeOffsetInLine(lines[eIdx], eChar) ?? { node: lines[eIdx], offset: lines[eIdx].childNodes.length }
- const range = document.createRange()
- range.setStart(s.node, s.offset)
- range.setEnd(e.node, e.offset)
- isProgrammaticSelection = true
- sel.removeAllRanges()
- sel.addRange(range)
- queueMicrotask(() => {
- isProgrammaticSelection = false
- })
- })
-
- // Build/toggle split layout and apply folding (both unified and split)
- createEffect(() => {
- const content = html()
- if (!container || !content) return
- const view = ctx.file.view(local.path)
-
- const pres = Array.from(container.querySelectorAll("pre"))
- if (pres.length === 0) return
- const originalPre = pres[0]
-
- const split = container.querySelector(".diff-split")
- if (view === "diff-split") {
- applySplitDiff(container)
- const next = container.querySelector(".diff-split")
- if (next) next.style.display = ""
- originalPre.style.display = "none"
- } else {
- if (split) split.style.display = "none"
- originalPre.style.display = ""
- }
-
- const expanded = ctx.file.folded(local.path)
- if (view === "diff-split") {
- const left = container.querySelector(".diff-split pre:nth-child(1) code")
- const right = container.querySelector(".diff-split pre:nth-child(2) code")
- if (left)
- applyDiffFolding(left, 3, { expanded, onExpand: (key) => ctx.file.unfold(local.path, key), side: "left" })
- if (right)
- applyDiffFolding(right, 3, { expanded, onExpand: (key) => ctx.file.unfold(local.path, key), side: "right" })
- } else {
- const code = container.querySelector("pre code")
- if (code)
- applyDiffFolding(code, 3, {
- expanded,
- onExpand: (key) => ctx.file.unfold(local.path, key),
- })
- }
- })
-
- // Highlight groups + scroll coupling
- const clearHighlights = () => {
- if (!container) return
- container.querySelectorAll(".diff-selected").forEach((el) => el.classList.remove("diff-selected"))
- }
-
- const applyHighlight = (idx: number, scroll?: boolean) => {
- if (!container) return
- const view = ctx.file.view(local.path)
- if (view === "raw") return
-
- clearHighlights()
-
- const nodes: HTMLElement[] = []
- if (view === "diff-split") {
- const left = container.querySelector(".diff-split pre:nth-child(1) code")
- const right = container.querySelector(".diff-split pre:nth-child(2) code")
- if (left)
- nodes.push(...Array.from(left.querySelectorAll(`[data-chgrp="${idx}"][data-diff="remove"]`)))
- if (right)
- nodes.push(...Array.from(right.querySelectorAll(`[data-chgrp="${idx}"][data-diff="add"]`)))
- } else {
- const code = container.querySelector("pre code")
- if (code) nodes.push(...Array.from(code.querySelectorAll(`[data-chgrp="${idx}"]`)))
- }
-
- for (const n of nodes) n.classList.add("diff-selected")
- if (scroll && nodes.length) nodes[0].scrollIntoView({ block: "center", behavior: "smooth" })
- }
-
- const countGroups = () => {
- if (!container) return 0
- const code = container.querySelector("pre code")
- if (!code) return 0
- const set = new Set()
- for (const el of Array.from(code.querySelectorAll(".diff-line[data-chgrp]"))) {
- const v = el.getAttribute("data-chgrp")
- if (v != undefined) set.add(v)
- }
- return set.size
- }
-
- let lastIdx: number | undefined = undefined
- let lastView: string | undefined
- let lastContent: string | undefined
- let lastRawIdx: number | undefined = undefined
- createEffect(() => {
- const content = html()
- if (!container || !content) return
- const view = ctx.file.view(local.path)
- const raw = ctx.file.changeIndex(local.path)
- if (raw === undefined) return
- const total = countGroups()
- if (total <= 0) return
- const next = ((raw % total) + total) % total
-
- const navigated = lastRawIdx !== undefined && lastRawIdx !== raw
-
- if (next !== raw) {
- ctx.file.setChangeIndex(local.path, next)
- applyHighlight(next, true)
- } else {
- if (lastView !== view || lastContent !== content) applyHighlight(next)
- if ((lastIdx !== undefined && lastIdx !== next) || navigated) applyHighlight(next, true)
- }
-
- lastRawIdx = raw
- lastIdx = next
- lastView = view
- lastContent = content
- })
-
- return (
- {
- container = el
- }}
- innerHTML={html()}
- class="
- font-mono text-xs tracking-wide overflow-y-auto h-full
- [&]:[counter-reset:line]
- [&_pre]:focus-visible:outline-none
- [&_pre]:overflow-x-auto [&_pre]:no-scrollbar
- [&_code]:min-w-full [&_code]:inline-block
- [&_.tab]:relative
- [&_.tab::before]:content['⇥']
- [&_.tab::before]:absolute
- [&_.tab::before]:opacity-0
- [&_.space]:relative
- [&_.space::before]:content-['·']
- [&_.space::before]:absolute
- [&_.space::before]:opacity-0
- [&_.line]:inline-block [&_.line]:w-full
- [&_.line]:hover:bg-background-element
- [&_.line::before]:sticky [&_.line::before]:left-0
- [&_.line::before]:w-12 [&_.line::before]:pr-4
- [&_.line::before]:z-10
- [&_.line::before]:bg-background-panel
- [&_.line::before]:text-text-muted/60
- [&_.line::before]:text-right [&_.line::before]:inline-block
- [&_.line::before]:select-none
- [&_.line::before]:[counter-increment:line]
- [&_.line::before]:content-[counter(line)]
- [&_.line-number-highlight]:bg-accent/20
- [&_.line-number-highlight::before]:bg-accent/40!
- [&_.line-number-highlight::before]:text-background-panel!
- [&_code.code-diff_.line::before]:content-['']
- [&_code.code-diff_.line::before]:w-0
- [&_code.code-diff_.line::before]:pr-0
- [&_.diff-split_code.code-diff::before]:w-10
- [&_.diff-split_.diff-newln]:left-0
- [&_.diff-oldln]:sticky [&_.diff-oldln]:left-0
- [&_.diff-oldln]:w-10 [&_.diff-oldln]:pr-2
- [&_.diff-oldln]:z-40
- [&_.diff-oldln]:text-text-muted/60
- [&_.diff-oldln]:text-right [&_.diff-oldln]:inline-block
- [&_.diff-oldln]:select-none
- [&_.diff-oldln]:bg-background-panel
- [&_.diff-newln]:sticky [&_.diff-newln]:left-10
- [&_.diff-newln]:w-10 [&_.diff-newln]:pr-2
- [&_.diff-newln]:z-40
- [&_.diff-newln]:text-text-muted/60
- [&_.diff-newln]:text-right [&_.diff-newln]:inline-block
- [&_.diff-newln]:select-none
- [&_.diff-newln]:bg-background-panel
- [&_.diff-add]:bg-success/20!
- [&_.diff-add.diff-selected]:bg-success/50!
- [&_.diff-add_.diff-oldln]:bg-success!
- [&_.diff-add_.diff-oldln]:text-background-panel!
- [&_.diff-add_.diff-newln]:bg-success!
- [&_.diff-add_.diff-newln]:text-background-panel!
- [&_.diff-remove]:bg-error/20!
- [&_.diff-remove.diff-selected]:bg-error/50!
- [&_.diff-remove_.diff-newln]:bg-error!
- [&_.diff-remove_.diff-newln]:text-background-panel!
- [&_.diff-remove_.diff-oldln]:bg-error!
- [&_.diff-remove_.diff-oldln]:text-background-panel!
- [&_.diff-sign]:inline-block [&_.diff-sign]:px-2 [&_.diff-sign]:select-none
- [&_.diff-blank]:bg-background-element
- [&_.diff-blank_.diff-oldln]:bg-background-element
- [&_.diff-blank_.diff-newln]:bg-background-element
- [&_.diff-collapsed]:block! [&_.diff-collapsed]:w-full [&_.diff-collapsed]:relative
- [&_.diff-collapsed]:select-none
- [&_.diff-collapsed]:bg-info/20 [&_.diff-collapsed]:hover:bg-info/40!
- [&_.diff-collapsed]:text-info/80 [&_.diff-collapsed]:hover:text-info
- [&_.diff-collapsed]:text-xs
- [&_.diff-collapsed_.diff-oldln]:bg-info!
- [&_.diff-collapsed_.diff-newln]:bg-info!
- "
- classList={{
- ...(local.classList || {}),
- [local.class ?? ""]: !!local.class,
- }}
- {...others}
- >
- )
-}
-
-function transformerUnifiedDiff(): ShikiTransformer {
- const kinds = new Map()
- const meta = new Map()
- let isDiff = false
-
- return {
- name: "unified-diff",
- preprocess(input) {
- kinds.clear()
- meta.clear()
- isDiff = false
-
- const ls = input.split(/\r?\n/)
- const out: Array = []
- let oldNo = 0
- let newNo = 0
- let inHunk = false
-
- for (let i = 0; i < ls.length; i++) {
- const s = ls[i]
-
- const m = s.match(/^@@\s*-(\d+)(?:,(\d+))?\s+\+(\d+)(?:,(\d+))?\s*@@/)
- if (m) {
- isDiff = true
- inHunk = true
- oldNo = parseInt(m[1], 10)
- newNo = parseInt(m[3], 10)
- continue
- }
-
- if (
- /^diff --git /.test(s) ||
- /^Index: /.test(s) ||
- /^--- /.test(s) ||
- /^\+\+\+ /.test(s) ||
- /^[=]{3,}$/.test(s) ||
- /^\*{3,}$/.test(s) ||
- /^\\ No newline at end of file$/.test(s)
- ) {
- isDiff = true
- continue
- }
-
- if (!inHunk) {
- out.push(s)
- continue
- }
-
- if (/^\+/.test(s)) {
- out.push(s)
- const ln = out.length
- kinds.set(ln, "add")
- meta.set(ln, { new: newNo, sign: "+" })
- newNo++
- continue
- }
-
- if (/^-/.test(s)) {
- out.push(s)
- const ln = out.length
- kinds.set(ln, "remove")
- meta.set(ln, { old: oldNo, sign: "-" })
- oldNo++
- continue
- }
-
- if (/^ /.test(s)) {
- out.push(s)
- const ln = out.length
- kinds.set(ln, "context")
- meta.set(ln, { old: oldNo, new: newNo })
- oldNo++
- newNo++
- continue
- }
-
- // fallback in hunks
- out.push(s)
- }
-
- return out.join("\n").trimEnd()
- },
- code(node) {
- if (isDiff) this.addClassToHast(node, "code-diff")
- },
- pre(node) {
- if (isDiff) this.addClassToHast(node, "code-diff")
- },
- line(node, line) {
- if (!isDiff) return
- const kind = kinds.get(line)
- if (!kind) return
-
- const m = meta.get(line) || {}
-
- this.addClassToHast(node, "diff-line")
- this.addClassToHast(node, `diff-${kind}`)
- node.properties = node.properties || {}
- ;(node.properties as any)["data-diff"] = kind
- if (m.old != undefined) (node.properties as any)["data-old"] = String(m.old)
- if (m.new != undefined) (node.properties as any)["data-new"] = String(m.new)
-
- const oldSpan = {
- type: "element",
- tagName: "span",
- properties: { className: ["diff-oldln"] },
- children: [{ type: "text", value: m.old != undefined ? String(m.old) : " " }],
- }
- const newSpan = {
- type: "element",
- tagName: "span",
- properties: { className: ["diff-newln"] },
- children: [{ type: "text", value: m.new != undefined ? String(m.new) : " " }],
- }
-
- if (kind === "add" || kind === "remove" || kind === "context") {
- const first = (node.children && (node.children as any[])[0]) as any
- if (first && first.type === "element" && first.children && first.children.length > 0) {
- const t = first.children[0]
- if (t && t.type === "text" && typeof t.value === "string" && t.value.length > 0) {
- const ch = t.value[0]
- if (ch === "+" || ch === "-" || ch === " ") t.value = t.value.slice(1)
- }
- }
- }
-
- const signSpan = {
- type: "element",
- tagName: "span",
- properties: { className: ["diff-sign"] },
- children: [{ type: "text", value: (m as any).sign || " " }],
- }
-
- // @ts-expect-error hast typing across versions
- node.children = [oldSpan, newSpan, signSpan, ...(node.children || [])]
- },
- }
-}
-
-function transformerDiffGroups(): ShikiTransformer {
- let group = -1
- let inGroup = false
- return {
- name: "diff-groups",
- pre() {
- group = -1
- inGroup = false
- },
- line(node) {
- const props = (node.properties || {}) as any
- const kind = props["data-diff"] as string | undefined
- if (kind === "add" || kind === "remove") {
- if (!inGroup) {
- group += 1
- inGroup = true
- }
- ;(node.properties as any)["data-chgrp"] = String(group)
- } else {
- inGroup = false
- }
- },
- }
-}
-
-function applyDiffFolding(
- root: HTMLElement,
- context = 3,
- options?: { expanded?: string[]; onExpand?: (key: string) => void; side?: "left" | "right" },
-) {
- if (!root.classList.contains("code-diff")) return
-
- // Cleanup: unwrap previous collapsed blocks and remove toggles
- const blocks = Array.from(root.querySelectorAll(".diff-collapsed-block"))
- for (const block of blocks) {
- const p = block.parentNode
- if (!p) {
- block.remove()
- continue
- }
- while (block.firstChild) p.insertBefore(block.firstChild, block)
- block.remove()
- }
- const toggles = Array.from(root.querySelectorAll(".diff-collapsed"))
- for (const t of toggles) t.remove()
-
- const lines = Array.from(root.querySelectorAll(".diff-line"))
- if (lines.length === 0) return
-
- const n = lines.length
- const isChange = lines.map((l) => l.dataset["diff"] === "add" || l.dataset["diff"] === "remove")
- const isContext = lines.map((l) => l.dataset["diff"] === "context")
- if (!isChange.some(Boolean)) return
-
- const visible = new Array(n).fill(false) as boolean[]
- for (let i = 0; i < n; i++) if (isChange[i]) visible[i] = true
- for (let i = 0; i < n; i++) {
- if (isChange[i]) {
- const s = Math.max(0, i - context)
- const e = Math.min(n - 1, i + context)
- for (let j = s; j <= e; j++) if (isContext[j]) visible[j] = true
- }
- }
-
- type Range = { start: number; end: number }
- const ranges: Range[] = []
- let i = 0
- while (i < n) {
- if (!visible[i] && isContext[i]) {
- let j = i
- while (j + 1 < n && !visible[j + 1] && isContext[j + 1]) j++
- ranges.push({ start: i, end: j })
- i = j + 1
- } else {
- i++
- }
- }
-
- for (const r of ranges) {
- const start = lines[r.start]
- const end = lines[r.end]
- const count = r.end - r.start + 1
- const minCollapse = 20
- if (count < minCollapse) {
- continue
- }
-
- // Wrap the entire collapsed chunk (including trailing newline) so it takes no space
- const block = document.createElement("span")
- block.className = "diff-collapsed-block"
- start.parentElement?.insertBefore(block, start)
-
- let cur: Node | undefined = start
- while (cur) {
- const next: Node | undefined = cur.nextSibling || undefined
- block.appendChild(cur)
- if (cur === end) {
- // Also move the newline after the last line into the block
- if (next && next.nodeType === Node.TEXT_NODE && (next.textContent || "").startsWith("\n")) {
- block.appendChild(next)
- }
- break
- }
- cur = next
- }
-
- block.style.display = "none"
- const row = document.createElement("span")
- row.className = "line diff-collapsed"
- row.setAttribute("data-kind", "collapsed")
- row.setAttribute("data-count", String(count))
- row.setAttribute("tabindex", "0")
- row.setAttribute("role", "button")
-
- const oldln = document.createElement("span")
- oldln.className = "diff-oldln"
- oldln.textContent = " "
-
- const newln = document.createElement("span")
- newln.className = "diff-newln"
- newln.textContent = " "
-
- const sign = document.createElement("span")
- sign.className = "diff-sign"
- sign.textContent = "…"
-
- const label = document.createElement("span")
- label.textContent = `show ${count} unchanged line${count > 1 ? "s" : ""}`
-
- const key = `o${start.dataset["old"] || ""}-${end.dataset["old"] || ""}:n${start.dataset["new"] || ""}-${end.dataset["new"] || ""}`
-
- const show = (record = true) => {
- if (record) options?.onExpand?.(key)
- const p = block.parentNode
- if (p) {
- while (block.firstChild) p.insertBefore(block.firstChild, block)
- block.remove()
- }
- row.remove()
- }
-
- row.addEventListener("click", () => show(true))
- row.addEventListener("keydown", (ev) => {
- if (ev.key === "Enter" || ev.key === " ") {
- ev.preventDefault()
- show(true)
- }
- })
-
- block.parentElement?.insertBefore(row, block)
- if (!options?.side || options.side === "left") row.appendChild(oldln)
- if (!options?.side || options.side === "right") row.appendChild(newln)
- row.appendChild(sign)
- row.appendChild(label)
-
- if (options?.expanded && options.expanded.includes(key)) {
- show(false)
- }
- }
-}
-
-function applySplitDiff(container: HTMLElement) {
- const pres = Array.from(container.querySelectorAll("pre"))
- if (pres.length === 0) return
- const originalPre = pres[0]
- const originalCode = originalPre.querySelector("code") as HTMLElement | undefined
- if (!originalCode || !originalCode.classList.contains("code-diff")) return
-
- // Rebuild split each time to match current content
- const existing = container.querySelector(".diff-split")
- if (existing) existing.remove()
-
- const grid = document.createElement("div")
- grid.className = "diff-split grid grid-cols-2 gap-x-6"
-
- const makeColumn = () => {
- const pre = document.createElement("pre")
- pre.className = originalPre.className
- const code = document.createElement("code")
- code.className = originalCode.className
- pre.appendChild(code)
- return { pre, code }
- }
-
- const left = makeColumn()
- const right = makeColumn()
-
- // Helpers
- const cloneSide = (line: HTMLElement, side: "old" | "new"): HTMLElement => {
- const clone = line.cloneNode(true) as HTMLElement
- const oldln = clone.querySelector(".diff-oldln")
- const newln = clone.querySelector(".diff-newln")
- if (side === "old") {
- if (newln) newln.remove()
- } else {
- if (oldln) oldln.remove()
- }
- return clone
- }
-
- const blankLine = (side: "old" | "new", kind: "add" | "remove"): HTMLElement => {
- const span = document.createElement("span")
- span.className = "line diff-line diff-blank"
- span.setAttribute("data-diff", kind)
- const ln = document.createElement("span")
- ln.className = side === "old" ? "diff-oldln" : "diff-newln"
- ln.textContent = " "
- span.appendChild(ln)
- return span
- }
-
- const lines = Array.from(originalCode.querySelectorAll(".diff-line"))
- let i = 0
- while (i < lines.length) {
- const cur = lines[i]
- const kind = cur.dataset["diff"]
-
- if (kind === "context") {
- left.code.appendChild(cloneSide(cur, "old"))
- left.code.appendChild(document.createTextNode("\n"))
- right.code.appendChild(cloneSide(cur, "new"))
- right.code.appendChild(document.createTextNode("\n"))
- i++
- continue
- }
-
- if (kind === "remove") {
- // Batch consecutive removes and following adds, then pair
- const removes: HTMLElement[] = []
- const adds: HTMLElement[] = []
- let j = i
- while (j < lines.length && lines[j].dataset["diff"] === "remove") {
- removes.push(lines[j])
- j++
- }
- let k = j
- while (k < lines.length && lines[k].dataset["diff"] === "add") {
- adds.push(lines[k])
- k++
- }
-
- const pairs = Math.min(removes.length, adds.length)
- for (let p = 0; p < pairs; p++) {
- left.code.appendChild(cloneSide(removes[p], "old"))
- left.code.appendChild(document.createTextNode("\n"))
- right.code.appendChild(cloneSide(adds[p], "new"))
- right.code.appendChild(document.createTextNode("\n"))
- }
- for (let p = pairs; p < removes.length; p++) {
- left.code.appendChild(cloneSide(removes[p], "old"))
- left.code.appendChild(document.createTextNode("\n"))
- right.code.appendChild(blankLine("new", "remove"))
- right.code.appendChild(document.createTextNode("\n"))
- }
- for (let p = pairs; p < adds.length; p++) {
- left.code.appendChild(blankLine("old", "add"))
- left.code.appendChild(document.createTextNode("\n"))
- right.code.appendChild(cloneSide(adds[p], "new"))
- right.code.appendChild(document.createTextNode("\n"))
- }
-
- i = k
- continue
- }
-
- if (kind === "add") {
- // Run of adds not preceded by removes
- const adds: HTMLElement[] = []
- let j = i
- while (j < lines.length && lines[j].dataset["diff"] === "add") {
- adds.push(lines[j])
- j++
- }
- for (let p = 0; p < adds.length; p++) {
- left.code.appendChild(blankLine("old", "add"))
- left.code.appendChild(document.createTextNode("\n"))
- right.code.appendChild(cloneSide(adds[p], "new"))
- right.code.appendChild(document.createTextNode("\n"))
- }
- i = j
- continue
- }
-
- // Any other kind: mirror as context
- left.code.appendChild(cloneSide(cur, "old"))
- left.code.appendChild(document.createTextNode("\n"))
- right.code.appendChild(cloneSide(cur, "new"))
- right.code.appendChild(document.createTextNode("\n"))
- i++
- }
-
- grid.appendChild(left.pre)
- grid.appendChild(right.pre)
- container.appendChild(grid)
-}
diff --git a/packages/desktop/src/components/file-tree.tsx b/packages/desktop/src/components/file-tree.tsx
index a5d19f51..1347ecae 100644
--- a/packages/desktop/src/components/file-tree.tsx
+++ b/packages/desktop/src/components/file-tree.tsx
@@ -77,7 +77,7 @@ export default function FileTree(props: {
(open ? local.file.expand(node.path) : local.file.collapse(node.path))}
>
@@ -85,7 +85,7 @@ export default function FileTree(props: {
diff --git a/packages/desktop/src/components/message-progress.tsx b/packages/desktop/src/components/message-progress.tsx
index c0037f57..a9be2ae5 100644
--- a/packages/desktop/src/components/message-progress.tsx
+++ b/packages/desktop/src/components/message-progress.tsx
@@ -70,9 +70,8 @@ export function MessageProgress(props: { assistantMessages: () => AssistantMessa
const lastPart = createMemo(() => resolvedParts().slice(-1)?.at(0))
const rawStatus = createMemo(() => {
- const defaultStatus = "Working..."
const last = lastPart()
- if (!last) return defaultStatus
+ if (!last) return undefined
if (last.type === "tool") {
switch (last.tool) {
@@ -102,7 +101,7 @@ export function MessageProgress(props: { assistantMessages: () => AssistantMessa
} else if (last.type === "text") {
return "Gathering thoughts..."
}
- return defaultStatus
+ return undefined
})
const [status, setStatus] = createSignal(rawStatus())
@@ -111,11 +110,11 @@ export function MessageProgress(props: { assistantMessages: () => AssistantMessa
createEffect(() => {
const newStatus = rawStatus()
- if (newStatus === status()) return
+ if (newStatus === status() || !newStatus) return
const timeSinceLastChange = Date.now() - lastStatusChange
- if (timeSinceLastChange >= 1000) {
+ if (timeSinceLastChange >= 1500) {
setStatus(newStatus)
lastStatusChange = Date.now()
if (statusTimeout) {
@@ -145,7 +144,7 @@ export function MessageProgress(props: { assistantMessages: () => AssistantMessa
{/* )} */}
{/* */}
- {status()}
+ {status() ?? "Considering next steps..."}
0}>
void
class?: string
ref?: (el: HTMLDivElement) => void
}
export const PromptInput: Component
= (props) => {
+ const navigate = useNavigate()
+ const sdk = useSDK()
+ const sync = useSync()
const local = useLocal()
+ const session = useSession()
let editorRef!: HTMLDivElement
- const defaultParts = [{ type: "text", content: "", start: 0, end: 0 } as const]
const [store, setStore] = createStore<{
- contentParts: ContentPart[]
popoverIsOpen: boolean
}>({
- contentParts: defaultParts,
popoverIsOpen: false,
})
- const isEmpty = createMemo(() => isEqual(store.contentParts, defaultParts))
+ createEffect(() => {
+ session.id
+ editorRef.focus()
+ })
+
const isFocused = createFocusSignal(() => editorRef)
const handlePaste = (event: ClipboardEvent) => {
@@ -71,14 +61,16 @@ export const PromptInput: Component = (props) => {
}
})
+ const handleFileSelect = (path: string | undefined) => {
+ if (!path) return
+ addPart({ type: "file", path, content: "@" + getFilename(path), start: 0, end: 0 })
+ setStore("popoverIsOpen", false)
+ }
+
const { flat, active, onInput, onKeyDown, refetch } = useFilteredList({
items: local.file.searchFilesAndDirectories,
key: (x) => x,
- onSelect: (path) => {
- if (!path) return
- addPart({ type: "file", path, content: "@" + getFilename(path), start: 0, end: 0 })
- setStore("popoverIsOpen", false)
- },
+ onSelect: handleFileSelect,
})
createEffect(() => {
@@ -88,10 +80,10 @@ export const PromptInput: Component = (props) => {
createEffect(
on(
- () => store.contentParts,
+ () => session.prompt.current(),
(currentParts) => {
const domParts = parseFromDOM()
- if (isEqual(currentParts, domParts)) return
+ if (isPromptEqual(currentParts, domParts)) return
const selection = window.getSelection()
let cursorPosition: number | null = null
@@ -122,8 +114,18 @@ export const PromptInput: Component = (props) => {
),
)
- const parseFromDOM = (): ContentPart[] => {
- const newParts: ContentPart[] = []
+ createEffect(
+ on(
+ () => session.prompt.cursor(),
+ (cursor) => {
+ if (cursor === undefined) return
+ queueMicrotask(() => setCursorPosition(editorRef, cursor))
+ },
+ ),
+ )
+
+ const parseFromDOM = (): Prompt => {
+ const newParts: Prompt = []
let position = 0
editorRef.childNodes.forEach((node) => {
if (node.nodeType === Node.TEXT_NODE) {
@@ -150,7 +152,7 @@ export const PromptInput: Component = (props) => {
}
}
})
- if (newParts.length === 0) newParts.push(...defaultParts)
+ if (newParts.length === 0) newParts.push(...DEFAULT_PROMPT)
return newParts
}
@@ -167,12 +169,13 @@ export const PromptInput: Component = (props) => {
setStore("popoverIsOpen", false)
}
- setStore("contentParts", rawParts)
+ session.prompt.set(rawParts, cursorPosition)
}
const addPart = (part: ContentPart) => {
const cursorPosition = getCursorPosition(editorRef)
- const rawText = store.contentParts.map((p) => p.content).join("")
+ const prompt = session.prompt.current()
+ const rawText = prompt.map((p) => p.content).join("")
const textBeforeCursor = rawText.substring(0, cursorPosition)
const atMatch = textBeforeCursor.match(/@(\S*)$/)
@@ -198,7 +201,7 @@ export const PromptInput: Component = (props) => {
parts: nextParts,
inserted,
cursorPositionAfter,
- } = store.contentParts.reduce(
+ } = prompt.reduce(
(acc, item) => {
if (acc.inserted) {
acc.parts.push({ ...item, start: acc.runningIndex, end: acc.runningIndex + item.content.length })
@@ -257,7 +260,7 @@ export const PromptInput: Component = (props) => {
)
if (!inserted) {
- const baseParts = store.contentParts.filter((item) => !(item.type === "text" && item.content === ""))
+ const baseParts = prompt.filter((item) => !(item.type === "text" && item.content === ""))
const runningIndex = baseParts.reduce((sum, p) => sum + p.content.length, 0)
const appendedAcc = { parts: [...baseParts] as ContentPart[], runningIndex }
if (part.type === "text") {
@@ -270,20 +273,27 @@ export const PromptInput: Component = (props) => {
end: appendedAcc.runningIndex + part.content.length,
})
}
- const next = appendedAcc.parts.length > 0 ? appendedAcc.parts : defaultParts
- setStore("contentParts", next)
- setStore("popoverIsOpen", false)
+ const next = appendedAcc.parts.length > 0 ? appendedAcc.parts : DEFAULT_PROMPT
const nextCursor = rawText.length + part.content.length
+ session.prompt.set(next, nextCursor)
+ setStore("popoverIsOpen", false)
queueMicrotask(() => setCursorPosition(editorRef, nextCursor))
return
}
- setStore("contentParts", nextParts)
+ session.prompt.set(nextParts, cursorPositionAfter)
setStore("popoverIsOpen", false)
queueMicrotask(() => setCursorPosition(editorRef, cursorPositionAfter))
}
+ const abort = () =>
+ sdk.client.session.abort({
+ path: {
+ id: session.id!,
+ },
+ })
+
const handleKeyDown = (event: KeyboardEvent) => {
if (store.popoverIsOpen && (event.key === "ArrowUp" || event.key === "ArrowDown" || event.key === "Enter")) {
onKeyDown(event)
@@ -293,14 +303,100 @@ export const PromptInput: Component = (props) => {
if (event.key === "Enter" && !event.shiftKey) {
handleSubmit(event)
}
+ if (event.key === "Escape") {
+ if (store.popoverIsOpen) {
+ setStore("popoverIsOpen", false)
+ } else if (session.working()) {
+ abort()
+ }
+ }
}
- const handleSubmit = (event: Event) => {
+ const handleSubmit = async (event: Event) => {
event.preventDefault()
- if (store.contentParts.length > 0) {
- props.onSubmit([...store.contentParts])
- setStore("contentParts", defaultParts)
+ const prompt = session.prompt.current()
+ const text = prompt.map((part) => part.content).join("")
+ if (text.trim().length === 0) {
+ if (session.working()) abort()
+ return
}
+
+ let existing = session.info()
+ if (!existing) {
+ const created = await sdk.client.session.create()
+ existing = created.data ?? undefined
+ if (existing) navigate(`/session/${existing.id}`)
+ }
+ if (!existing) return
+
+ // if (!session.id) {
+ // session.layout.setOpenedTabs(
+ // session.layout.copyTabs("", session.id)
+ // }
+
+ const toAbsolutePath = (path: string) => (path.startsWith("/") ? path : sync.absolute(path))
+ const attachments = prompt.filter((part) => part.type === "file")
+
+ // const activeFile = local.context.active()
+ // if (activeFile) {
+ // registerAttachment(
+ // activeFile.path,
+ // activeFile.selection,
+ // activeFile.name ?? formatAttachmentLabel(activeFile.path, activeFile.selection),
+ // )
+ // }
+
+ // for (const contextFile of local.context.all()) {
+ // registerAttachment(
+ // contextFile.path,
+ // contextFile.selection,
+ // formatAttachmentLabel(contextFile.path, contextFile.selection),
+ // )
+ // }
+
+ const attachmentParts = attachments.map((attachment) => {
+ const absolute = toAbsolutePath(attachment.path)
+ const query = attachment.selection
+ ? `?start=${attachment.selection.startLine}&end=${attachment.selection.endLine}`
+ : ""
+ return {
+ type: "file" as const,
+ mime: "text/plain",
+ url: `file://${absolute}${query}`,
+ filename: getFilename(attachment.path),
+ source: {
+ type: "file" as const,
+ text: {
+ value: attachment.content,
+ start: attachment.start,
+ end: attachment.end,
+ },
+ path: absolute,
+ },
+ }
+ })
+
+ session.layout.setActiveTab(undefined)
+ session.messages.setActive(undefined)
+ session.prompt.set(DEFAULT_PROMPT, 0)
+
+ sdk.client.session.prompt({
+ path: { id: existing.id },
+ body: {
+ agent: local.agent.current()!.name,
+ model: {
+ modelID: local.model.current()!.id,
+ providerID: local.model.current()!.provider.id,
+ },
+ parts: [
+ {
+ type: "text",
+ text,
+ },
+ ...attachmentParts,
+ ],
+ },
+ })
}
return (
@@ -310,11 +406,12 @@ export const PromptInput: Component = (props) => {
0} fallback={No matching files
}>
{(i) => (
- handleFileSelect(i)}
>
@@ -326,7 +423,7 @@ export const PromptInput: Component
= (props) => {
-
+
)}
@@ -354,7 +451,7 @@ export const PromptInput: Component = (props) => {
"[&>[data-type=file]]:text-icon-info-active": true,
}}
/>
-
+
Plan and build anything
@@ -419,29 +516,39 @@ export const PromptInput: Component = (props) => {
)}
-