Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions changelog.d/347-invite-not-found-wording.fixed.md
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Add friend no longer calls an unknown, mistyped or truncated invite link "already used": the "wasn't found" message is shown as written, and only a really used invite says it was already used (#347).
2 changes: 1 addition & 1 deletion docs/subsystems/social.md
Original file line number Diff line number Diff line change
Expand Up @@ -128,7 +128,7 @@ pins the list. The authority for the list is Bot Social's README and `docs/FACE_

### Add friend invite input (#310)

`social/join-invite` runs the box text through `parseInviteInput` (`social.js`) before `join_invite`. It takes `https://host/i/CODE`, the same without the scheme, a link whose `/i/` is missing (host plus one bare token), a bare code, or the whole copied invite text (the first token with `/i/` or a URL wins), and sends only the code: Bot Social's `join_invite` looks up a code (it strips just a leading `…/i/`), so no host is ever built or added. Copy invite link hands out the server's `invite.url` through `inviteLink`, which rebuilds `origin/i/CODE` if a server ever answered a url without `/i/`; Bot Social itself always emits `/i/CODE` (`inviteUrl`) and serves only that route, so a link without `/i/` comes from hand-trimming or a client that dropped it. A pasted host that is not `config.server` is kept as `host`; a not-found then says the link may come from another server. `mapJoinInviteError` turns `invite_not_found`, expired / revoked / used invites, an own invite, `blocked` and `rate_limited` into one short sentence each ("This invite link wasn't found. It may be incomplete, expired, or already used. Ask your friend for a new link."); anything else passes through unchanged.
`social/join-invite` runs the box text through `parseInviteInput` (`social.js`) before `join_invite`. It takes `https://host/i/CODE`, the same without the scheme, a link whose `/i/` is missing (host plus one bare token), a bare code, or the whole copied invite text (the first token with `/i/` or a URL wins), and sends only the code: Bot Social's `join_invite` looks up a code (it strips just a leading `…/i/`), so no host is ever built or added. Copy invite link hands out the server's `invite.url` through `inviteLink`, which rebuilds `origin/i/CODE` if a server ever answered a url without `/i/`; Bot Social itself always emits `/i/CODE` (`inviteUrl`) and serves only that route, so a link without `/i/` comes from hand-trimming or a client that dropped it. A pasted host that is not `config.server` is kept as `host`; a not-found then says the link may come from another server. `mapJoinInviteError` turns `invite_not_found`, expired / revoked / used invites, an own invite, `blocked` and `rate_limited` into one short sentence each ("This invite link wasn't found. It may be incomplete, expired, or already used. Ask your friend for a new link."); anything else passes through unchanged. The client (`plugins/social/client.js`) shows those sentences as written (#347): `errorText` relabels a message as "This invite was already used" only for the raw server words (`invite_unavailable`, `invite is used`, `invite_used`), never for the not-found sentence, which itself mentions "already used" as one possible cause; `run()` keeps its "… failed:" prefix for every other message and drops it only for the "already used" and "already friends" sentences.

### Thinking status for friends' Bots (#297)

Expand Down
6 changes: 4 additions & 2 deletions plugins/social/client.js
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,9 @@ window.__ModuleLoader__.load({
}
const message = String(e?.message ?? e ?? '')
if (/relationship_exists/i.test(message)) return "You're already friends. Their Bot is back in your list."
if (/invite_unavailable|invite is used|invite_used|already used/i.test(message)) return 'This invite was already used. Ask your friend for a new one.'
// Only the raw server words map here. The "invite wasn't found" sentence also says "already used" (as one of its possible
// causes), so matching those words would relabel every unknown or mistyped link as a used one.
if (/invite_unavailable|invite is used|invite_used/i.test(message)) return 'This invite was already used. Ask your friend for a new one.'

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Badge Add the required social subsystem documentation

This behavior change modifies files owned by the social subsystem, but the commit neither updates docs/subsystems/social.md nor includes a Docs-not-needed: trailer. Running ARCH_DOCS_BASE=d6203fde9325f262131c54b106b9053af70b303a node core/scripts/check-arch-docs.mjs reports both changed social files and exits with failure, so the required lint/verify pipeline cannot pass until the subsystem documentation is updated or the explicit trailer is added.

AGENTS.md reference: AGENTS.md:L92-L94

Useful? React with 👍 / 👎.

return message
}

Expand Down Expand Up @@ -1375,7 +1377,7 @@ window.__ModuleLoader__.load({
onChange?.()
} catch (e) {
const text = errorText(e)
setStatus({ tone: 'error', text: /already used|already friends/i.test(text) ? text : `${label} failed: ${text}` })
setStatus({ tone: 'error', text: /^This invite was already used|^You're already friends/.test(text) ? text : `${label} failed: ${text}` })
} finally {
setBusy(false)
}
Expand Down
6 changes: 6 additions & 0 deletions plugins/social/test/social.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -522,6 +522,12 @@ test('client.js registers a sidebar section and @ rows into the FlyBot registry'
// Transport errors are worded in English from their code, never the localized host text.
assert.match(plugin.errorText(Object.assign(new Error('请求失败(HTTP 404)'), { code: 'HTTP_404' })), /^The FlyBot host did not answer \(HTTP 404\)/)
assert.equal(plugin.errorText(Object.assign(new Error('x'), { code: 'bot/refused' })), 'x')
// #310 follow-up: the "wasn't found" sentence mentions "already used" as one possible cause; it must not be shown as "already used".
const notFound = "This invite link wasn't found. It may be incomplete, expired, or already used. Ask your friend for a new link."
assert.equal(plugin.errorText(Object.assign(new Error(notFound), { code: 'bot/refused' })), notFound)
assert.equal(plugin.errorText(new Error("This invite link wasn't found on your Bot Social server. It may come from another server, or be incomplete, expired, or already used. Ask your friend for a new link.")).startsWith("This invite link wasn't found on your Bot Social server"), true)
assert.equal(plugin.errorText(new Error('This invite was already used. Ask your friend for a new one.')), 'This invite was already used. Ask your friend for a new one.')
assert.equal(plugin.errorText(new Error('Bot Social join_invite: invite is used')), 'This invite was already used. Ask your friend for a new one.')
// A missing host handler is never shown as "Unknown FlyBot endpoint".
assert.match(plugin.errorText(Object.assign(new Error('Unknown FlyBot endpoint social/remote-bots'), { code: 'bot/not-found' })), /^Social is not running:/)
assert.doesNotMatch(plugin.errorText(Object.assign(new Error('Unknown FlyBot endpoint social/remote-bots'), { code: 'bot/not-found' })), /Unknown FlyBot endpoint/)
Expand Down
Loading