summaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorKit Langton <[email protected]>2026-04-17 16:15:24 -0400
committerGitHub <[email protected]>2026-04-17 20:15:24 +0000
commit984f5ed6eb0cbf3048d8c1dbd8f643f5a01d2501 (patch)
treef8eba3906f82ec8e77cb6ff7e3ec31ce4479ae25
parentc2061c6bbfa83147792ab9aec251cf193ccb6b0d (diff)
downloadopencode-984f5ed6eb0cbf3048d8c1dbd8f643f5a01d2501.tar.gz
opencode-984f5ed6eb0cbf3048d8c1dbd8f643f5a01d2501.zip
fix(opencode): skip share sync for unshared sessions (#23159)
-rw-r--r--packages/opencode/src/share/share-next.ts41
1 files changed, 33 insertions, 8 deletions
diff --git a/packages/opencode/src/share/share-next.ts b/packages/opencode/src/share/share-next.ts
index 3484d5da7..2622f4f7f 100644
--- a/packages/opencode/src/share/share-next.ts
+++ b/packages/opencode/src/share/share-next.ts
@@ -38,8 +38,9 @@ const ShareSchema = Schema.Struct({
export type Share = typeof ShareSchema.Type
type State = {
- queue: Map<string, { data: Map<string, Data> }>
+ queue: Map<SessionID, Map<string, Data>>
scope: Scope.Closeable
+ shared: Map<SessionID, Share | null>
}
type Data =
@@ -118,17 +119,20 @@ export const layer = Layer.effect(
function sync(sessionID: SessionID, data: Data[]): Effect.Effect<void> {
return Effect.gen(function* () {
if (disabled) return
+ const share = yield* getCached(sessionID)
+ if (!share) return
+
const s = yield* InstanceState.get(state)
const existing = s.queue.get(sessionID)
if (existing) {
for (const item of data) {
- existing.data.set(key(item), item)
+ existing.set(key(item), item)
}
return
}
const next = new Map(data.map((item) => [key(item), item]))
- s.queue.set(sessionID, { data: next })
+ s.queue.set(sessionID, next)
yield* flush(sessionID).pipe(
Effect.delay(1000),
Effect.catchCause((cause) =>
@@ -143,13 +147,14 @@ export const layer = Layer.effect(
const state: InstanceState.InstanceState<State> = yield* InstanceState.make<State>(
Effect.fn("ShareNext.state")(function* (_ctx) {
- const cache: State = { queue: new Map(), scope: yield* Scope.make() }
+ const cache: State = { queue: new Map(), scope: yield* Scope.make(), shared: new Map() }
yield* Effect.addFinalizer(() =>
Scope.close(cache.scope, Exit.void).pipe(
Effect.andThen(
Effect.sync(() => {
cache.queue.clear()
+ cache.shared.clear()
}),
),
),
@@ -227,6 +232,18 @@ export const layer = Layer.effect(
return { id: row.id, secret: row.secret, url: row.url } satisfies Share
})
+ const getCached = Effect.fnUntraced(function* (sessionID: SessionID) {
+ const s = yield* InstanceState.get(state)
+ if (s.shared.has(sessionID)) {
+ const cached = s.shared.get(sessionID)
+ return cached === null ? undefined : cached
+ }
+
+ const share = yield* get(sessionID)
+ s.shared.set(sessionID, share ?? null)
+ return share
+ })
+
const flush = Effect.fn("ShareNext.flush")(function* (sessionID: SessionID) {
if (disabled) return
const s = yield* InstanceState.get(state)
@@ -235,13 +252,13 @@ export const layer = Layer.effect(
s.queue.delete(sessionID)
- const share = yield* get(sessionID)
+ const share = yield* getCached(sessionID)
if (!share) return
const req = yield* request()
const res = yield* HttpClientRequest.post(`${req.baseUrl}${req.api.sync(share.id)}`).pipe(
HttpClientRequest.setHeaders(req.headers),
- HttpClientRequest.bodyJson({ secret: share.secret, data: Array.from(queued.data.values()) }),
+ HttpClientRequest.bodyJson({ secret: share.secret, data: Array.from(queued.values()) }),
Effect.flatMap((r) => http.execute(r)),
)
@@ -307,6 +324,7 @@ export const layer = Layer.effect(
.run(),
)
const s = yield* InstanceState.get(state)
+ s.shared.set(sessionID, result)
yield* full(sessionID).pipe(
Effect.catchCause((cause) =>
Effect.sync(() => {
@@ -321,8 +339,13 @@ export const layer = Layer.effect(
const remove = Effect.fn("ShareNext.remove")(function* (sessionID: SessionID) {
if (disabled) return
log.info("removing share", { sessionID })
- const share = yield* get(sessionID)
- if (!share) return
+ const s = yield* InstanceState.get(state)
+ const share = yield* getCached(sessionID)
+ if (!share) {
+ s.shared.delete(sessionID)
+ s.queue.delete(sessionID)
+ return
+ }
const req = yield* request()
yield* HttpClientRequest.delete(`${req.baseUrl}${req.api.remove(share.id)}`).pipe(
@@ -332,6 +355,8 @@ export const layer = Layer.effect(
)
yield* db((db) => db.delete(SessionShareTable).where(eq(SessionShareTable.session_id, sessionID)).run())
+ s.shared.delete(sessionID)
+ s.queue.delete(sessionID)
})
return Service.of({ init, url, request, create, remove })