diff --git a/packages/sidecar/src/commands.ts b/packages/sidecar/src/commands.ts index 8760a5b..ae8dd6e 100644 --- a/packages/sidecar/src/commands.ts +++ b/packages/sidecar/src/commands.ts @@ -113,7 +113,9 @@ export async function resolveRoomyOrigin(service: string, fetcher: typeof fetch const response = await fetcher(didUrl) if (!response.ok) throw new Error(`Could not resolve Roomy service (${response.status})`) const document = await response.json() as { service?: Array<{ id?: unknown; serviceEndpoint?: unknown }> } - const endpoint = document.service?.find((entry) => entry.id === `${service}#space_roomy_appserver`)?.serviceEndpoint + const endpoint = document.service?.find((entry) => + entry.id === '#space_roomy_appserver' || entry.id === `${service}#space_roomy_appserver` + )?.serviceEndpoint if (typeof endpoint !== 'string' || !endpoint.startsWith('https://')) throw new Error('Roomy DID document has no HTTPS appserver endpoint') return new URL(endpoint).origin } diff --git a/packages/sidecar/test/roomy-origin.test.mjs b/packages/sidecar/test/roomy-origin.test.mjs new file mode 100644 index 0000000..47c83d5 --- /dev/null +++ b/packages/sidecar/test/roomy-origin.test.mjs @@ -0,0 +1,18 @@ +import assert from 'node:assert/strict' +import { describe, it } from 'node:test' +import { resolveRoomyOrigin } from '../dist/index.js' + +const response = (body) => new Response(JSON.stringify(body)) + +describe('Roomy appserver origin', () => { + for (const id of ['#space_roomy_appserver', 'did:web:api.roomy.space#space_roomy_appserver']) { + it(`resolves the ${id.startsWith('#') ? 'relative' : 'absolute'} DID service id`, async () => { + const fetcher = async (input) => { + assert.equal(String(input), 'https://api.roomy.space/.well-known/did.json') + return response({ service: [{ id, serviceEndpoint: 'https://roomy.example/xrpc' }] }) + } + + assert.equal(await resolveRoomyOrigin('did:web:api.roomy.space', fetcher), 'https://roomy.example') + }) + } +}) diff --git a/packages/ui/src/lib/roomy.test.ts b/packages/ui/src/lib/roomy.test.ts index 2ce6ed9..26de78c 100644 --- a/packages/ui/src/lib/roomy.test.ts +++ b/packages/ui/src/lib/roomy.test.ts @@ -12,7 +12,7 @@ describe('Roomy browser reader', () => { it('resolves the DID, skips malformed rows, and reports truncation', async () => { const fetcher: typeof fetch = async (input) => { const url = String(input) - if (url.includes('did.json')) return response({ service: [{ id: 'did:web:roomy.example#space_roomy_appserver', serviceEndpoint: 'https://api.roomy.example' }] }) + if (url.includes('did.json')) return response({ service: [{ id: '#space_roomy_appserver', serviceEndpoint: 'https://api.roomy.example' }] }) if (url.includes('getMetadata')) return response({ name: 'Design thread' }) return response({ messages: [{ id: 'm1', authorDid: 'did:plc:a', content: 'hello', timestamp: '2026-01-01T00:00:00Z' }, { nope: true }], cursor: 'older' }) } diff --git a/packages/ui/src/lib/roomy.ts b/packages/ui/src/lib/roomy.ts index 09f37c4..323d50e 100644 --- a/packages/ui/src/lib/roomy.ts +++ b/packages/ui/src/lib/roomy.ts @@ -48,7 +48,9 @@ export function resolveRoomyOrigin(service: string, fetcher: typeof fetch = fetc try { response = await fetcher(url) } catch { throw new RoomyError('unreachable', 'The Roomy service could not be reached.') } if (!response.ok) throw new RoomyError('unreachable', `The Roomy service DID could not be resolved (${response.status}).`) const document = await response.json() as { service?: Array<{ id?: unknown; serviceEndpoint?: unknown }> } - const endpoint = document.service?.find((entry) => entry.id === `${service}#space_roomy_appserver`)?.serviceEndpoint + const endpoint = document.service?.find((entry) => + entry.id === '#space_roomy_appserver' || entry.id === `${service}#space_roomy_appserver` + )?.serviceEndpoint if (typeof endpoint !== 'string' || !endpoint.startsWith('https://')) throw new RoomyError('invalid', 'The Roomy service has no HTTPS appserver endpoint.') return new URL(endpoint).origin })()