keep the stored pds url when a refresh delivers no did doc
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
@@ -242,6 +242,36 @@ function dyingData(refreshJwt: string): SessionData {
|
||||
}
|
||||
}
|
||||
|
||||
/** The rotated payload PasswordSession threads through its `onUpdated` hook. */
|
||||
function refreshedData(
|
||||
refreshJwt: string,
|
||||
didDoc?: SessionData['didDoc'],
|
||||
): SessionData {
|
||||
return {
|
||||
accessJwt: 'fresh-access-jwt',
|
||||
refreshJwt,
|
||||
handle: 'alice.test',
|
||||
did: DID,
|
||||
active: true,
|
||||
service: SERVICE,
|
||||
...(didDoc ? {didDoc} : {}),
|
||||
}
|
||||
}
|
||||
|
||||
/** A minimal valid DID document whose only service entry is a PDS. */
|
||||
function makeDidDoc(pdsUrl: string): SessionData['didDoc'] {
|
||||
return {
|
||||
id: DID,
|
||||
service: [
|
||||
{
|
||||
id: '#atproto_pds',
|
||||
type: 'AtprotoPersonalDataServer',
|
||||
serviceEndpoint: pdsUrl,
|
||||
},
|
||||
],
|
||||
}
|
||||
}
|
||||
|
||||
beforeEach(() => {
|
||||
mockPersisted.session = {accounts: [], currentAccount: undefined}
|
||||
mockPersisted.latest = {accounts: [], currentAccount: undefined}
|
||||
@@ -366,6 +396,59 @@ describe('expiry rescue', () => {
|
||||
})
|
||||
})
|
||||
|
||||
/*
|
||||
* A refresh payload only carries a didDoc when the server sends one, but
|
||||
* `pdsUrl` is never derived from the login service. If the provider does not
|
||||
* thread the stored value through, an ordinary refresh persists
|
||||
* `pdsUrl: undefined` and the next cold start routes pre-refresh requests to
|
||||
* the entryway instead of the account's PDS.
|
||||
*/
|
||||
describe('refresh persistence', () => {
|
||||
const PDS_HOST = 'https://shimeji.us-east.host.bsky.network'
|
||||
const DIDDOC_PDS_HOST = 'https://morel.us-west.host.bsky.network'
|
||||
|
||||
it('keeps the stored pdsUrl when the refresh carries no didDoc', async () => {
|
||||
const account = makeAccount({pdsUrl: `${PDS_HOST}/`})
|
||||
const bundle = makeBundle(account)
|
||||
const {onSessionChange, currentAccount} = await renderLoggedIn(
|
||||
account,
|
||||
bundle,
|
||||
)
|
||||
|
||||
act(() => {
|
||||
onSessionChange(
|
||||
bundle as unknown as SessionBundle,
|
||||
DID,
|
||||
'update',
|
||||
refreshedData('refresh-jwt-2'),
|
||||
)
|
||||
})
|
||||
|
||||
expect(currentAccount()?.refreshJwt).toBe('refresh-jwt-2')
|
||||
expect(currentAccount()?.pdsUrl).toBe(`${PDS_HOST}/`)
|
||||
})
|
||||
|
||||
it('prefers the didDoc endpoint over the stored pdsUrl', async () => {
|
||||
const account = makeAccount({pdsUrl: `${PDS_HOST}/`})
|
||||
const bundle = makeBundle(account)
|
||||
const {onSessionChange, currentAccount} = await renderLoggedIn(
|
||||
account,
|
||||
bundle,
|
||||
)
|
||||
|
||||
act(() => {
|
||||
onSessionChange(
|
||||
bundle as unknown as SessionBundle,
|
||||
DID,
|
||||
'update',
|
||||
refreshedData('refresh-jwt-2', makeDidDoc(DIDDOC_PDS_HOST)),
|
||||
)
|
||||
})
|
||||
|
||||
expect(currentAccount()?.pdsUrl).toBe(`${DIDDOC_PDS_HOST}/`)
|
||||
})
|
||||
})
|
||||
|
||||
/** Deliver a cross-tab `persisted` update to the provider's newest listener. */
|
||||
function emitSynced(session: Schema['session']) {
|
||||
mockPersistedListeners[mockPersistedListeners.length - 1](session)
|
||||
|
||||
@@ -161,10 +161,19 @@ export function Provider({children}: React.PropsWithChildren<{}>) {
|
||||
/*
|
||||
* PasswordSession invokes its hooks before updating its live getter. Use
|
||||
* the delivered payload so a refresh persists the newly rotated tokens.
|
||||
*
|
||||
* A refresh payload carries no didDoc unless the server sends one, so the
|
||||
* stored account's `pdsUrl` is threaded in as the fallback. Without it the
|
||||
* refresh would persist `pdsUrl: undefined` and the next cold start would
|
||||
* route pre-refresh requests to the entryway instead of the PDS.
|
||||
*/
|
||||
const refreshedAccount =
|
||||
sessionEvent === 'update' && sessionData
|
||||
? sessionDataToSessionAccount(sessionData, sessionData.service)
|
||||
? sessionDataToSessionAccount(
|
||||
sessionData,
|
||||
sessionData.service,
|
||||
store.getState().accounts.find(a => a.did === accountDid)?.pdsUrl,
|
||||
)
|
||||
: undefined
|
||||
|
||||
/*
|
||||
|
||||
Reference in New Issue
Block a user