Dax Raad 9 months ago
parent
commit
e9bad39a7e

+ 1 - 0
app/infra/app.ts

@@ -13,6 +13,7 @@ export const api = new sst.cloudflare.Worker("Api", {
   link: [bucket],
   transform: {
     worker: (args) => {
+      args.logpush = true
       args.bindings = $resolve(args.bindings).apply((bindings) => [
         ...bindings,
         {

+ 19 - 15
app/packages/function/src/api.ts

@@ -2,12 +2,13 @@ import { DurableObject } from "cloudflare:workers"
 import { randomUUID } from "node:crypto"
 import { Resource } from "sst"
 
-type Bindings = {
+type Env = {
   SYNC_SERVER: DurableObjectNamespace<SyncServer>
+  Bucket: R2Bucket
 }
 
-export class SyncServer extends DurableObject {
-  constructor(ctx: DurableObjectState, env: Bindings) {
+export class SyncServer extends DurableObject<Env> {
+  constructor(ctx: DurableObjectState, env: Env) {
     super(ctx, env)
   }
   async fetch() {
@@ -18,14 +19,10 @@ export class SyncServer extends DurableObject {
 
     this.ctx.acceptWebSocket(server)
 
-    setTimeout(async () => {
-      const data = await this.ctx.storage.list({
-        prefix: "data/",
-      })
-      for (const [key, content] of Object.entries(data)) {
-        server.send(JSON.stringify({ key, content }))
-      }
-    }, 0)
+    const data = await this.ctx.storage.list()
+    for (const [key, content] of data.entries()) {
+      server.send(JSON.stringify({ key, content }))
+    }
 
     return new Response(null, {
       status: 101,
@@ -49,11 +46,17 @@ export class SyncServer extends DurableObject {
       return new Response("Error: Invalid key", { status: 400 })
 
     // store message
-    await Resource.Bucket.put(`${key}.json`, JSON.stringify(content))
-    await this.ctx.storage.put("data/" + key, content)
+    await this.env.Bucket.put(`share/${key}.json`, JSON.stringify(content), {
+      httpMetadata: {
+        contentType: "application/json",
+      },
+    })
+    await this.ctx.storage.put(key, content)
     const clients = this.ctx.getWebSockets()
     console.log("SyncServer publish", key, "to", clients.length, "subscribers")
-    clients.forEach((client) => client.send(JSON.stringify({ key, content })))
+    for (const client of clients) {
+      client.send(JSON.stringify({ key, content }))
+    }
   }
 
   public async share(sessionID: string) {
@@ -90,7 +93,7 @@ export class SyncServer extends DurableObject {
 }
 
 export default {
-  async fetch(request: Request, env: Bindings, ctx: ExecutionContext) {
+  async fetch(request: Request, env: Env, ctx: ExecutionContext) {
     const url = new URL(request.url)
     const splits = url.pathname.split("/")
     const method = splits[1]
@@ -155,6 +158,7 @@ export default {
         })
       }
       const id = url.searchParams.get("id")
+      console.log("share_poll", id)
       if (!id)
         return new Response("Error: Share ID is required", { status: 400 })
       const stub = env.SYNC_SERVER.get(env.SYNC_SERVER.idFromName(id))

+ 4 - 9
app/packages/web/src/components/Share.tsx

@@ -26,7 +26,6 @@ import {
   IconPencilSquare,
   IconWrenchScrewdriver,
 } from "./icons"
-import CodeBlock from "./CodeBlock"
 import DiffView from "./DiffView"
 import styles from "./share.module.css"
 import { type UIMessage } from "ai"
@@ -219,7 +218,7 @@ function PartFooter(props: { time: number }) {
 
 export default function Share(props: { api: string }) {
   let params = new URLSearchParams(document.location.search)
-  const sessionId = params.get("id")
+  const id = params.get("id")
 
   const [store, setStore] = createStore<{
     info?: SessionInfo
@@ -233,12 +232,8 @@ export default function Share(props: { api: string }) {
   onMount(() => {
     const apiUrl = props.api
 
-    console.log("Mounting Share component with ID:", sessionId)
-    console.log("API URL:", apiUrl)
-
-    if (!sessionId) {
-      console.error("Session ID not found in environment variables")
-      setConnectionStatus(["error", "Session ID not found"])
+    if (!id) {
+      setConnectionStatus(["error", "id not found"])
       return
     }
 
@@ -262,7 +257,7 @@ export default function Share(props: { api: string }) {
 
       // Always use secure WebSocket protocol (wss)
       const wsBaseUrl = apiUrl.replace(/^https?:\/\//, "wss://")
-      const wsUrl = `${wsBaseUrl}/share_poll?id=${sessionId}`
+      const wsUrl = `${wsBaseUrl}/share_poll?id=${id}`
       console.log("Connecting to WebSocket URL:", wsUrl)
 
       // Create WebSocket connection

+ 0 - 0
app/packages/web/src/pages/share/index.astro → app/packages/web/src/pages/s/index.astro


+ 4 - 1
internal/tui/components/chat/sidebar.go

@@ -53,7 +53,10 @@ func (m *sidebarCmp) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
 func (m *sidebarCmp) View() string {
 	t := theme.CurrentTheme()
 	baseStyle := styles.BaseStyle()
-	shareUrl := baseStyle.Foreground(t.TextMuted()).Render("https://dev.opencode.ai/share?id=" + m.app.Session.Id)
+	shareUrl := ""
+	if m.app.Session.Share != nil {
+		shareUrl = baseStyle.Foreground(t.TextMuted()).Render(m.app.Session.Share.Url)
+	}
 
 	// qrcode := ""
 	// if m.app.Session.ShareID != nil {

+ 31 - 3
pkg/client/gen/openapi.json

@@ -775,16 +775,44 @@
             "type": "string",
             "pattern": "^ses"
           },
-          "shareID": {
-            "type": "string"
+          "share": {
+            "type": "object",
+            "properties": {
+              "secret": {
+                "type": "string"
+              },
+              "url": {
+                "type": "string"
+              }
+            },
+            "required": [
+              "secret",
+              "url"
+            ]
           },
           "title": {
             "type": "string"
+          },
+          "time": {
+            "type": "object",
+            "properties": {
+              "created": {
+                "type": "number"
+              },
+              "updated": {
+                "type": "number"
+              }
+            },
+            "required": [
+              "created",
+              "updated"
+            ]
           }
         },
         "required": [
           "id",
-          "title"
+          "title",
+          "time"
         ]
       },
       "Provider.Info": {

+ 10 - 3
pkg/client/generated-client.go

@@ -194,9 +194,16 @@ type ProviderModel struct {
 
 // SessionInfo defines model for session.info.
 type SessionInfo struct {
-	Id      string  `json:"id"`
-	ShareID *string `json:"shareID,omitempty"`
-	Title   string  `json:"title"`
+	Id    string `json:"id"`
+	Share *struct {
+		Secret string `json:"secret"`
+		Url    string `json:"url"`
+	} `json:"share,omitempty"`
+	Time struct {
+		Created float32 `json:"created"`
+		Updated float32 `json:"updated"`
+	} `json:"time"`
+	Title string `json:"title"`
 }
 
 // PostSessionAbortJSONBody defines parameters for PostSessionAbort.