mirror of
https://github.com/block/buzz.git
synced 2026-11-15 13:51:12 +00:00
fix(mobile): skip a starter whose id an archived channel holds
The relay refuses a kind:9007 whose `h` is an archived channel with `invalid: channel is archived`, before its duplicate check. Desktop and mobile create a starter at the same fixed id, so an archived starter there left invite setup in permanent recovery. Treat that refusal as an archived starter: join a live namesake if the reload shows one, else skip it. Co-authored-by: Larry <627498bd4bd1f281a16431e3c6cce3b5c25b6692798c78672298aefbf2f8f8b5@buzz.block.builderlab.xyz> Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Signed-off-by: Logan Johnson <loganj@squareup.com>
This commit is contained in:
@@ -157,7 +157,10 @@ class MobileInviteJoinRecovery implements InviteJoinRecovery {
|
||||
_ensureScopeCurrent();
|
||||
} catch (error) {
|
||||
final nameTaken = _isChannelNameTakenError(error);
|
||||
if (!nameTaken && !_isDuplicateChannelError(error)) rethrow;
|
||||
final archivedAtId = _isArchivedChannelError(error);
|
||||
if (!nameTaken && !archivedAtId && !_isDuplicateChannelError(error)) {
|
||||
rethrow;
|
||||
}
|
||||
_ensureScopeCurrent();
|
||||
channels = await _loadChannels();
|
||||
_ensureScopeCurrent();
|
||||
@@ -168,6 +171,10 @@ class MobileInviteJoinRecovery implements InviteJoinRecovery {
|
||||
.firstOrNull ??
|
||||
(nameTaken ? _findListedNamesake(channels, starter.slug) : null);
|
||||
if (holder == null) {
|
||||
// The relay refuses a create at an archived channel's id before
|
||||
// its duplicate check, and keeps that id, so the starter can never
|
||||
// be created there.
|
||||
if (archivedAtId) continue;
|
||||
// The directory omits archived channels, yet the relay still
|
||||
// keeps the id (desktop uses the same one), so a duplicate with
|
||||
// no match may be an archived starter. Read that id directly.
|
||||
@@ -228,6 +235,11 @@ bool _isUsableStarter(Channel channel) =>
|
||||
bool _isDuplicateChannelError(Object error) =>
|
||||
error.toString().contains('duplicate: channel already exists');
|
||||
|
||||
/// The relay refuses any channel event whose `h` is an archived channel,
|
||||
/// a create at that id included: `invalid: channel is archived`.
|
||||
bool _isArchivedChannelError(Object error) =>
|
||||
error.toString().contains('invalid: channel is archived');
|
||||
|
||||
/// The relay refuses creating an open channel whose name another listed
|
||||
/// channel already holds, ignoring case:
|
||||
/// `invalid: an open channel named "general" already exists`.
|
||||
|
||||
@@ -496,6 +496,20 @@ void main() {
|
||||
expect(archivedAtId.loads(), 2);
|
||||
expect(focusAfterArchived, welcomeId);
|
||||
|
||||
// The relay refuses a create at an archived channel's id with
|
||||
// `channel is archived`; that starter is skipped without a lookup.
|
||||
final refusedAsArchived = starterSetup(
|
||||
channelsOnLoad: (_) => const [],
|
||||
refusalError: 'invalid: channel is archived',
|
||||
);
|
||||
final focusAfterRefusal = await refusedAsArchived.recovery
|
||||
.ensureStarterChannels();
|
||||
expect(refusedAsArchived.created, ['general', 'welcome-everyone']);
|
||||
expect(refusedAsArchived.lookups, isEmpty);
|
||||
expect(refusedAsArchived.joined, isEmpty);
|
||||
expect(refusedAsArchived.loads(), 2);
|
||||
expect(focusAfterRefusal, welcomeId);
|
||||
|
||||
// The scope fence also holds across the direct lookup, checked on the
|
||||
// last starter so the next starter's own fence cannot mask it.
|
||||
var lookedUp = false;
|
||||
|
||||
Reference in New Issue
Block a user