mirror of
https://github.com/bookorbit/bookorbit.git
synced 2026-11-03 00:11:37 -06:00
fbaf0b63df
The iOS app lets an account reach one server through several addresses, such as a home network IP and a public name. Before it sends credentials to an alternative address it needs to know the address leads to the same installation, so expose a public, credential-free GET /server-identity returning a persisted UUID, and add the same optional instanceId to app-info with the server-connection-identity feature flag. The UUID lives in a singleton server_identity row shared by every replica, created on first use and cached per process. An unreadable identity omits instanceId instead of failing app-info, which clients rely on for feature detection. Existing routes and bodies are unchanged and the web client does not call the new route; the iOS app does. The migration uses IF NOT EXISTS because an unreleased build created the same table as 0109.
22 lines
1.2 KiB
TypeScript
22 lines
1.2 KiB
TypeScript
import { ServerIdentityRepository } from './server-identity.repository';
|
|
import { ServerIdentityService } from './server-identity.service';
|
|
|
|
describe('ServerIdentityService', () => {
|
|
it('shares the durable identity across concurrent requests', async () => {
|
|
const getOrCreate = vi.fn().mockResolvedValue('538a27ca-87ef-47bc-a195-13c8597c3529');
|
|
const service = new ServerIdentityService({ getOrCreate } as unknown as ServerIdentityRepository);
|
|
const [first, second] = await Promise.all([service.getIdentity(), service.getIdentity()]);
|
|
expect(first).toEqual({ product: 'bookorbit', protocolVersion: 1, instanceId: '538a27ca-87ef-47bc-a195-13c8597c3529' });
|
|
expect(second).toEqual(first);
|
|
expect(getOrCreate).toHaveBeenCalledOnce();
|
|
});
|
|
|
|
it('retries after a failed database read', async () => {
|
|
const getOrCreate = vi.fn().mockRejectedValueOnce(new Error('unavailable')).mockResolvedValue('restored');
|
|
const service = new ServerIdentityService({ getOrCreate } as unknown as ServerIdentityRepository);
|
|
await expect(service.getIdentity()).rejects.toThrow('unavailable');
|
|
expect((await service.getIdentity()).instanceId).toBe('restored');
|
|
expect(getOrCreate).toHaveBeenCalledTimes(2);
|
|
});
|
|
});
|