diff --git a/infra/lake.ts b/infra/lake.ts index c62bb1556..4e9489ba0 100644 --- a/infra/lake.ts +++ b/infra/lake.ts @@ -268,6 +268,7 @@ export const lakeIngest = new sst.Linkable("LakeIngest", { secret: ingestSecret.result, }, }) +export const lakeIngestSecret = new sst.Secret("LakeIngestSecret", ingestSecret.result) export const lakeQueryPermissions = [ { @@ -320,3 +321,39 @@ export const lakeQueryPermissions = [ resources: ["*"], }, ] + +//////////////// +// S3 Tables +//////////////// + +const modelsNamespace = new aws.s3tables.Namespace("LakeModelsNamespace", { + namespace: "models", + tableBucketArn: tableBucket.arn, +}) + +new aws.s3tables.Table( + "LakeModelsEventTable", + { + name: "hit", + namespace: modelsNamespace.namespace, + tableBucketArn: modelsNamespace.tableBucketArn, + format: "ICEBERG", + metadata: { + iceberg: { + schema: { + fields: [ + { name: "event_timestamp", type: "string", required: false }, + { name: "event_date", type: "string", required: false }, + { name: "event_type", type: "string", required: false }, + { name: "country", type: "string", required: false }, + { name: "user_agent", type: "string", required: false }, + { name: "ip", type: "string", required: false }, + { name: "ip_prefix", type: "string", required: false }, + { name: "path", type: "string", required: false }, + ], + }, + }, + }, + }, + { deleteBeforeReplace: $app.stage !== "production" }, +) diff --git a/infra/stats.ts b/infra/stats.ts index 107e8b9f2..f7bdf322c 100644 --- a/infra/stats.ts +++ b/infra/stats.ts @@ -1,11 +1,6 @@ import { lakeAthenaWorkgroup, lakeCatalog, lakeCluster, lakeQueryPermissions, lakeRegion, tableBucket } from "./lake" import { EMAILOCTOPUS_API_KEY } from "./app" - -const domain = (() => { - if ($app.stage === "production") return "stats.opencode.ai" - if ($app.stage === "dev") return "stats.dev.opencode.ai" - return `stats.${$app.stage}.dev.opencode.ai` -})() +import { domain } from "./stage" //////////////// // LAKE @@ -42,6 +37,7 @@ const inferenceEventTable = new aws.s3tables.Table( { name: "request_length", type: "long", required: false }, { name: "status", type: "int", required: false }, { name: "ip", type: "string", required: false }, + { name: "ip_prefix", type: "string", required: false }, { name: "is_stream", type: "boolean", required: false }, { name: "session", type: "string", required: false }, { name: "request", type: "string", required: false }, @@ -167,10 +163,10 @@ new sst.x.DevCommand("StatsStudio", { export const app = new sst.cloudflare.x.SolidStart("Stats", { path: "packages/stats/app", buildCommand: "bun run build", - domain, + domain: `stats.${domain}`, link: [database, EMAILOCTOPUS_API_KEY], environment: { - PUBLIC_URL: `https://${domain}/stats`, + PUBLIC_URL: `https://stats.${domain}/stats`, }, }) diff --git a/sst.config.ts b/sst.config.ts index a159fa304..214c55d53 100644 --- a/sst.config.ts +++ b/sst.config.ts @@ -30,7 +30,8 @@ export default $config({ async run() { const stage = await import("./infra/stage.js") await import("./infra/app.js") - const stats = stage.deployAws ? await import("./infra/lake.js").then(() => import("./infra/stats.js")) : undefined + const lake = stage.deployAws ? await import("./infra/lake.js") : undefined + const stats = stage.deployAws ? await import("./infra/stats.js") : undefined const { stat } = await import("./infra/console.js") await import("./infra/enterprise.js") if ($app.stage === "production" || $app.stage === "vimtor") { @@ -40,6 +41,12 @@ export default $config({ return { StatWorkerUrl: stat.url, ...(stats ? { StatsUrl: stats.app.url } : {}), + ...(lake + ? { + LakeUrl: lake.lakeIngest.properties.url, + LakeSecretName: lake.lakeIngestSecret.name, + } + : {}), AwsStage: stage.awsStage, } },