Răsfoiți Sursa

feat(stats): route stats app

Adam 2 luni în urmă
părinte
comite
58da1ea48e

+ 10 - 9
infra/stats.ts

@@ -1,4 +1,5 @@
 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"
@@ -163,15 +164,15 @@ new sst.x.DevCommand("StatsStudio", {
 // APP
 ////////////////
 
-// export const app = new sst.cloudflare.x.SolidStart("Stats", {
-//   path: "packages/stats/app",
-//   buildCommand: "bun run build",
-//   domain,
-//   link: [database],
-//   environment: {
-//     PUBLIC_URL: `https://${domain}`,
-//   },
-// })
+export const app = new sst.cloudflare.x.SolidStart("Stats", {
+  path: "packages/stats/app",
+  buildCommand: "bun run build",
+  domain,
+  link: [database, EMAILOCTOPUS_API_KEY],
+  environment: {
+    PUBLIC_URL: `https://${domain}/stats`,
+  },
+})
 
 ////////////////
 // SERVICES

+ 22 - 0
packages/console/app/src/routes/stats/[...path].ts

@@ -0,0 +1,22 @@
+import type { APIEvent } from "@solidjs/start/server"
+import { Resource } from "@opencode-ai/console-resource"
+
+async function handler(evt: APIEvent) {
+  const req = evt.request.clone()
+  const url = new URL(req.url)
+  const host = Resource.App.stage === "production" ? "stats.opencode.ai" : "stats.dev.opencode.ai"
+  const targetUrl = `https://${host}${url.pathname}${url.search}`
+
+  return fetch(targetUrl, {
+    method: req.method,
+    headers: req.headers,
+    body: req.body,
+  })
+}
+
+export const GET = handler
+export const POST = handler
+export const PUT = handler
+export const DELETE = handler
+export const OPTIONS = handler
+export const PATCH = handler

+ 22 - 0
packages/console/app/src/routes/stats/index.ts

@@ -0,0 +1,22 @@
+import type { APIEvent } from "@solidjs/start/server"
+import { Resource } from "@opencode-ai/console-resource"
+
+async function handler(evt: APIEvent) {
+  const req = evt.request.clone()
+  const url = new URL(req.url)
+  const host = Resource.App.stage === "production" ? "stats.opencode.ai" : "stats.dev.opencode.ai"
+  const targetUrl = `https://${host}${url.pathname}${url.search}`
+
+  return fetch(targetUrl, {
+    method: req.method,
+    headers: req.headers,
+    body: req.body,
+  })
+}
+
+export const GET = handler
+export const POST = handler
+export const PUT = handler
+export const DELETE = handler
+export const OPTIONS = handler
+export const PATCH = handler

+ 1 - 0
packages/stats/app/src/app.tsx

@@ -16,6 +16,7 @@ function AppMeta() {
 export default function App() {
   return (
     <Router
+      base={import.meta.env.BASE_URL.replace(/\/$/, "")}
       explicitLinks={true}
       root={(props) => (
         <MetaProvider>

+ 2 - 2
packages/stats/app/src/routes/index.tsx

@@ -1213,7 +1213,7 @@ function Header() {
   return (
     <header data-component="top" data-menu-open={menuOpen() ? "true" : undefined}>
       <div data-slot="header-bar">
-        <a data-slot="brand" href="/" aria-label="OpenCode home">
+        <a data-slot="brand" href={import.meta.env.BASE_URL} aria-label="Stats home">
           <StatsWordmark />
         </a>
         <nav data-component="section-nav" aria-label="Stats sections">
@@ -1436,7 +1436,7 @@ function SubscribeModal(props: { onClose: () => void }) {
               event.preventDefault()
               setStatus("pending")
               setMessage("")
-              fetch("/api/newsletter", {
+              fetch(`${import.meta.env.BASE_URL}api/newsletter`, {
                 method: "POST",
                 body: new FormData(event.currentTarget),
               }).then(

+ 1 - 0
packages/stats/app/src/routes/stats/api/health.ts

@@ -0,0 +1 @@
+export { GET } from "../../api/health"

+ 1 - 0
packages/stats/app/src/routes/stats/api/newsletter.ts

@@ -0,0 +1 @@
+export { POST } from "../../api/newsletter"

+ 1 - 0
packages/stats/app/vite.config.ts

@@ -3,6 +3,7 @@ import { nitro } from "nitro/vite"
 import { defineConfig, type PluginOption } from "vite"
 
 export default defineConfig({
+  base: "/stats/",
   plugins: [
     solidStart() as PluginOption,
     nitro({

+ 2 - 5
sst.config.ts

@@ -30,10 +30,7 @@ export default $config({
   async run() {
     const stage = await import("./infra/stage.js")
     await import("./infra/app.js")
-    if (stage.deployAws) {
-      await import("./infra/lake.js")
-      await import("./infra/stats.js")
-    }
+    const stats = stage.deployAws ? await import("./infra/lake.js").then(() => import("./infra/stats.js")) : undefined
     const { stat } = await import("./infra/console.js")
     await import("./infra/enterprise.js")
     if ($app.stage === "production" || $app.stage === "vimtor") {
@@ -42,7 +39,7 @@ export default $config({
 
     return {
       StatWorkerUrl: stat.url,
-      // StatsUrl: stats.app.url,
+      ...(stats ? { StatsUrl: stats.app.url } : {}),
       AwsStage: stage.awsStage,
     }
   },