From 575ab7bb197a16c26f89cc4ff591769406286f08 Mon Sep 17 00:00:00 2001 From: Luke Curley Date: Tue, 4 Aug 2026 13:38:13 -0700 Subject: [PATCH 1/2] docs(net): say who owns the broadcast behind Announce.Broadcast.active `active` hands out the same `Broadcast.Consumer` type that `consume()` returns, so nothing stops a caller from closing it. Doing so leaves `active` pointing at a dead consumer and every later read fails, while the path is still announced and a fresh consume() works. No in-tree caller does this, and the repo already has an idiom for the question (refcounted handles, clone() for an independent lifetime), so say which side of it `active` is on rather than reshaping the type. Co-Authored-By: Claude Opus 5 --- js/net/src/announced.ts | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/js/net/src/announced.ts b/js/net/src/announced.ts index ae3401093..129c58094 100644 --- a/js/net/src/announced.ts +++ b/js/net/src/announced.ts @@ -186,7 +186,14 @@ export class Broadcast { /** The broadcast path this handle watches. */ readonly path: Path.Valid; - /** The live broadcast, or `undefined` while it is offline. */ + /** + * The live broadcast, or `undefined` while it is offline. + * + * Borrowed, not yours to close: this handle owns the consumer and swaps it when the path is + * republished. Closing it leaves `active` pointing at a dead one, so reads fail until the + * next announcement replaces it. Take a {@link broadcast.Consumer.clone} for a lifetime of + * your own, or close this whole handle to release everything. + */ readonly active: Getter; #active = new Signal(undefined); From 7bd6a4aa1ab8001cada369e2cff5d7ec74c3e7f8 Mon Sep 17 00:00:00 2001 From: Luke Curley Date: Tue, 4 Aug 2026 13:54:49 -0700 Subject: [PATCH 2/2] docs(net): qualify what closing the borrowed consumer costs Consumers are reference-counted, so closing the one read from `active` only kills the shared broadcast when it was the last reference; with a clone outstanding, reads through the closed handle still work. Say that rather than promising reads fail. Co-Authored-By: Claude Opus 5 --- js/net/src/announced.ts | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/js/net/src/announced.ts b/js/net/src/announced.ts index 129c58094..b9eaf6d4b 100644 --- a/js/net/src/announced.ts +++ b/js/net/src/announced.ts @@ -190,9 +190,10 @@ export class Broadcast { * The live broadcast, or `undefined` while it is offline. * * Borrowed, not yours to close: this handle owns the consumer and swaps it when the path is - * republished. Closing it leaves `active` pointing at a dead one, so reads fail until the - * next announcement replaces it. Take a {@link broadcast.Consumer.clone} for a lifetime of - * your own, or close this whole handle to release everything. + * republished. `active` keeps pointing at whatever you closed, so once you drop the last + * reference the shared broadcast is gone and reads fail until the next announcement replaces + * it. Take a {@link broadcast.Consumer.clone} for a lifetime of your own, or close this whole + * handle to release everything. */ readonly active: Getter;